Home > Back-end >  Add new child element using xsl 3.0
Add new child element using xsl 3.0

Time:05-19

I need to transform following xml as Expected Output using xsl 3.0 or xsl 2.0. Need to add new element called <key> </key> for each <row> element by combining its legacyID and company.

Input XML:

<AggregatedData>
   <Data>
      <Entry>
         <legacyID>ABC</legacyID>
         <AssociateID>123</AssociateID>
      </Entry>
      <Entry>
         <legacyID>CDE</legacyID>
         <AssociateID>456</AssociateID>
      </Entry>
   </Data>
   <root>
      <row>
         <legacyID>ABC</legacyID>
         <company>Test Company 1</company>
         <firstname>Test1</firstname>
      </row>
      <row>
         <legacyID>CDE</legacyID>
         <company>Test Company 2</company>
         <firstname>Test2</firstname>
      </row>
   </root>
</AggregatedData>

Expected Output:

<AggregatedData>
   <Data>
      <Entry>
         <legacyID>ABC<legacyID>
         <AssociateID>123<AssociateID>
      <Entry>
      <Entry>
         <legacyID>CDE</legacyID>
         <AssociateID>456</AssociateID>
      </Entry>
   </Data>
   <root>
      <row>
         <key>ABC_Test Company 1</key>
         <legacyID>ABC</legacyID>
         <company>Test Company 1</company>
         <firstname>Test1</firstname>
      </row>
      <row>
         <key>ABC_Test Company 2</key>
         <legacyID>CDE</legacyID>
         <company>Test Company 2</company>
         <firstname>Test2</firstname>
      </row>
   </root>
</AggregatedData>

I used following xsl code,

<?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" encoding="utf-8" indent="yes" omit-xml-declaration="yes" />
   <xsl:template match="root/*">
      <xsl:copy>
         <xsl:element name="key">
            <xsl:value-of select="concat(//root/row/legacyID,' ',/row/company)" />
         </xsl:element>
         <xsl:call-template name="copy-children" />
      </xsl:copy>
   </xsl:template>
   <!-- Copy the children of the current node. -->
   <xsl:template name="copy-children">
      <xsl:copy-of select="./*" />
   </xsl:template>
   <!-- Generic identity template -->
   <xsl:template match="node()|@*">
      <xsl:copy>
         <xsl:apply-templates select="@*" />
         <xsl:apply-templates />
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

But this gave the output like below,

<?xml version="1.0" encoding="UTF-8"?>
<AggregatedData>
   <Data>
      <Entry>
         <legacyID>ABC</legacyID>
         <AssociateID>123</AssociateID>
      </Entry>
      <Entry>
         <legacyID>CDE</legacyID>
         <AssociateID>456</AssociateID>
      </Entry>
   </Data>
   <root>
      <row>
         <key>ABC_Test Company 1</key>
         <legacyID>ABC</legacyID>
         <company>Test Company 1</company>
         <firstname>Test1</firstname>
      </row>
      <row>
         <key>ABC_Test Company 1</key>
         <legacyID>CDE</legacyID>
         <company>Test Company 2</company>
         <firstname>Test2</firstname>
      </row>
   </root>
</AggregatedData>

According to above output both row values updated with the same key value. I need to correct that and need to use xsl 2.0.

CodePudding user response:

You could do it like this :

<?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="row">
    <xsl:copy>
      <key>
        <xsl:value-of select="concat(legacyID,'_',company)"/>
      </key>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
  
  <!-- Identity transform -->
  <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/

CodePudding user response:

In XSLT 3.0 you could reduce the code to:

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

<xsl:mode on-no-match="shallow-copy"/>

<xsl:template match="row/legacyID">
    <key>
        <xsl:value-of select="., ../company" separator="_"/>
    </key>
    <xsl:copy-of select="."/>
</xsl:template>
  
</xsl:stylesheet>
  • Related