简体   繁体   中英

Replace Specific XML Node value with ABC using XSLT

Sample XML:

<MAIN>
    <A>
        <first_name>Franklin</first_name>
        <first_name_Previous></first_name_Previous>
        <formal_name>Franklin Alagala </formal_name>
        <gender>M</gender>
        <is_overridden>false</is_overridden>
    </A>
    <B>
        <first_name>Franklin</first_name>
        <formal_name>Franklin Alagala </formal_name>
        <gender>M</gender>
        <gender_Previous></gender_Previous>
        <is_overridden>false</is_overridden>
    </B>
</MAIN>

Expected Output:

<MAIN>
    <A>
        <first_name>Franklin</first_name>
        <first_name_Previous>ABCD</first_name_Previous>
        <formal_name>Franklin Alagala </formal_name>
        <gender>M</gender>
        <is_overridden>false</is_overridden>
    </A>
    <B>
        <first_name>Franklin</first_name>
        <formal_name>Franklin Alagala </formal_name>
        <gender>M</gender>
        <gender_Previous>ABCD</gender_Previous>
        <is_overridden>false</is_overridden>
    </B>
</MAIN>

Want to replace the node which contains name as previous and the node is empty. However if the node contains name as previous and value is present it should leave the name as it is.

Let me put your description a little other way, which better leads to the expected solution.

  1. You look at each child element of MAIN ( A , B and possibly C , D and so on), let's call it buckets .

  2. Each bucket you want to process the following way:

    • Look at each its child element.
    • If this element has not empty text content, leave it unchanged.
    • Otherwise (this element has no text) read the content of an element with the same name but in the previous bucket.
    • If the value just read is not empty, set the text of the current element to that value.
    • Otherwise set the content of the current element to ABCD .

Then we can write the above rules in XSL as follows:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="MAIN/*/*">
    <xsl:copy>
      <xsl:call-template name="proc_node"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template name="proc_node">
    <xsl:variable name="thisName" select="name()"/>
    <xsl:variable name="cnt" select="string-length(.)"/>
    <xsl:if test="$cnt &gt; 0">
      <xsl:value-of select="."/>
    </xsl:if>
    <xsl:if test="$cnt = 0">
      <xsl:variable name="prevBucket" select="../preceding-sibling::*[1]"/>
      <xsl:variable name="prevElem" select="$prevBucket/*[name()=$thisName]"/>
      <xsl:variable name="cnt" select="string-length($prevElem)"/>
      <xsl:if test="$cnt &gt; 0">
        <xsl:value-of select="$prevElem"/>
      </xsl:if>
      <xsl:if test="$cnt = 0">ABCD</xsl:if>
    </xsl:if>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
  </xsl:template>
</xsl:transform>

I don't know how to locate the node having previous in the name.

Try:

*[contains(name(), 'Previous')]

If you want to further restrict this to empty elements, you can use:

*[contains(name(), 'Previous') and not(node())]

Note that XML is case-sensitive; "previous" is not the same thing as "Previous".

I have written the code which is working fine:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:date="http://exslt.org/dates-and-times" extension-element-prefixes="date">
    <xsl:output indent="yes" />
    <xsl:template match="@*|node()">
        <xsl:copy>
        <xsl:if test="contains(name(), '_previous')">
         <xsl:if test="not(string(.))">PREVIOUS</xsl:if>      
        </xsl:if>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM