Search code examples
xmlxsltxslt-2.0

Copy previous xml content and add a new tag if it's missing


It will be quite helpful if you can provide your best thoughts on xslt and the easiest way to achieve below output.

Case 1:-Under account/acc4300 if empid field is missing Solution:- Read the value of empid from account/Fintrans[1]/acc4300 and place it in account/acc4300

Case 2:-Under account/acc4300 if empid field is already there Solution:- Do Nothing

Case 3:- If account/acc4300 is missing Solution:- Do Nothing

Input XML:

<Root>
<corp att="abc">
    <account number="111">
        <acc4300>
            <name>stack</name>
            //empid tag is not present here as in first occurance, so I want to read it from below node of Fintrans and the value should be 5678 in output xml
        </acc4300>
        <Fintrans>
            <Amount>12.00</Amount>
            <Tax>1.00</Tax>
            <empid>5678</empid>
        </fintrans>
        <Fintrans>
            <Amount>112.00</Amount>
            <Tax>13.00</Tax>
            <empid>5678</empid>
        </fintrans>
    </account>
<account number="321">
        <acc4300>
            <name>stack1</name>
            //empid tag is not present here as in first occurance, so I want to read it from below node of Fintrans and the value should be 5678 in output xml
        </acc4300>
        <Fintrans>
            <Amount>152.00</Amount>
            <Tax>19.00</Tax>
            <empid>9734</empid>
        </fintrans>
        <Fintrans>
            <Amount>142.00</Amount>
            <Tax>17.00</Tax>
            <empid>9734</empid>
        </fintrans>
    </account>
    <account number="222">
        <acc4300>
            <name>overflow</name>
            <empid>1234</empid>
            // Do nothing to employee id as already in input file empid is present under node acc4300
        </acc4300>
        <Fintrans>
            <Amount>121.00</Amount>
            <Tax>15.00</Tax>
            <empid>1234</empid>
        </fintrans>
        <Fintrans>
            <Amount>122.00</Amount>
            <Tax>15.00</Tax>
            <empid>1234</empid>
        </fintrans>
    </account>
    <account number="333">
        //Since acc400 tag is missing in this block do nothing.
        <Fintrans>
            <Amount>12.00</Amount>
            <Tax>1.00</Tax>
            <empid>4285</empid>
        </fintrans>
        <Fintrans>
            <Amount>112.00</Amount>
            <Tax>13.00</Tax>
            <empid>4285</empid>
        </fintrans>
    </account>
</corp>
<corp att="asfd">
...........
...........
...........
</corp>
</Root>

Result Should look like below

<Root>
<corp att="abc">
    <account number="111">
        <acc4300>
            <name>stack</name>
            <empid>5678</empid>
        </acc4300>
        <Fintrans>
            <Amount>12.00</Amount>
            <Tax>1.00</Tax>
            <empid>5678</empid>
        </fintrans>
        <Fintrans>
            <Amount>112.00</Amount>
            <Tax>13.00</Tax>
            <empid>5678</empid>
        </fintrans>
    </account>
    <account number="321">
        <acc4300>
            <name>stack1</name>
            <empid>9734</empid>
        </acc4300>
        <Fintrans>
            <Amount>152.00</Amount>
            <Tax>19.00</Tax>
            <empid>9734</empid>
        </fintrans>
        <Fintrans>
            <Amount>142.00</Amount>
            <Tax>17.00</Tax>
            <empid>9734</empid>
        </fintrans>
    </account>
    <account number="222">
        <acc4300>
            <name>overflow</name>
            <empid>1234</empid>
        </acc4300>
        <Fintrans>
            <Amount>121.00</Amount>
            <Tax>15.00</Tax>
            <empid>1234</empid>
        </fintrans>
        <Fintrans>
            <Amount>122.00</Amount>
            <Tax>15.00</Tax>
            <empid>1234</empid>
        </fintrans>
    </account>
    <account number="333">
        <Fintrans>
            <Amount>12.00</Amount>
            <Tax>1.00</Tax>
            <empid>4285</empid>
        </fintrans>
        <Fintrans>
            <Amount>112.00</Amount>
            <Tax>13.00</Tax>
            <empid>4285</empid>
        </fintrans>
    </account>
</corp>
<corp att="asfd">
...........
...........
...........
</corp>
</Root>

Note:- This is a sample XML and I have over 500 other fields in original XML so writing XSLT for each and every node is not feasible. Kindly suggest any best possible way with Version 1.0 or 2.0 of XSLT.


Solution

  • Here's a way this could be done.

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
    
      <xsl:output method="xml" indent="yes"/>
    
      <xsl:template match="acc4300">
          <xsl:copy>
              <xsl:apply-templates/>
              <xsl:if test="not(empid)">
                  <empid><xsl:value-of select="../fintrans[1]/empid"/></empid>
              </xsl:if>
          </xsl:copy>
      </xsl:template>
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    See it working here : https://xsltfiddle.liberty-development.net/pNmC4J2/1