Search code examples
xslt

Merge XML Node based on Node ID


I have this xml:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <list>
        <customer>
            <id>1</id>
            <name>Peter</name>
        </customer>
        <customer>
            <id>2</id>
            <name>Klaus</name>
        </customer>
    </list>
    <orderList>
        <position>
            <id>1</id>
            <positionID>10</positionID>
            <price>100</price>
            <currency>EUR</currency>
        </position>
        <position>
            <id>2</id>
            <positionID>10</positionID>
            <price>200</price>
            <currency>YEN</currency>
        </position>
        <position>
            <id>2</id>
            <positionID>20</positionID>
            <price>300</price>
            <currency>YEN</currency>
        </position>
    </orderList>
</root>

this is my XSLT:

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

<xsl:key name="KeyID" match="position" use="id" />

<xsl:template match="/root">
    <root>
        <list>
            <xsl:for-each select="list/customer">
                <customer>
                    <xsl:copy-of select="*"/>
                    <position>
                        <item>
                            <xsl:copy-of select="key('KeyID', id)/price"/>
                            <xsl:copy-of select="key('KeyID', id)/currency"/>
                        </item>
                    </position>
                </customer>
            </xsl:for-each>
        </list>
    </root>
</xsl:template>

</xsl:stylesheet>

My goal is the following:

<root>
   <list>
      <customer>
         <id>1</id>
         <name>Peter</name>
         <position>
            <item>
                <price>100</price>
                <currency>EUR</currency>
            </item>
        </position>
      </customer>
      <customer>
         <id>2</id>
         <name>Klaus</name>
         <position>
            <item>
                 <price>200</price>
                 <currency>YEN</currency>
            </item>
            <item>
                 <price>300</price>
                 <currency>YEN</currency>
            </item>
        </position>
      </customer>
   </list>
</root>

Is there a quick, easy way to do this?

This is what i'am getting:

<root>
   <list>
      <customer>
         <id>1</id>
         <name>Peter</name>
         <position>
            <item>
               <price>100</price>
               <currency>EUR</currency>
            </item>
         </position>
      </customer>
      <customer>
         <id>2</id>
         <name>Klaus</name>
         <position>
            <item>
               <price>200</price>
               <price>300</price>
               <currency>YEN</currency>
               <currency>YEN</currency>
            </item>
         </position>
      </customer>
   </list>
</root>

However I cannot find any articles that demonstrate how to do this in xsl so I would be very greatful if someone could provide me with an example or link me an article that explains how to do this. Thanks in advance.


Solution

  • Short version:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:key name="KeyID" match="position" use="id" />
    
    <xsl:template match="/root">
        <root>
            <list>
                <xsl:for-each select="list/customer">
                    <customer>
                        <xsl:copy-of select="*"/>
                        <position>
                            <xsl:for-each select="key('KeyID', id)">
                                <item>
                                    <xsl:copy-of select="price|currency"/>
                                </item>
                            </xsl:for-each>
                        </position>
                    </customer>
                </xsl:for-each>
            </list>
        </root>
    </xsl:template>
    
    </xsl:stylesheet>