Search code examples
xslt-2.0xslt-grouping

Grouping and Identity transformation


How to apply identity transformation and grouping at the same time

  <items>
        <user>
          <id>8788989</id>
         <firstname>test</firstname>
         <lastname>user</lastname>
        </user>
        <info>test xml</info>
        <fromdate><fromdate>
        <todate></todate>

        <item id="123" name="Java">
            <price>1</price>
            <description></description> 
        </item>

        <item id="123" name="Java and XML">
            <price>2</price>
            <description></description> 
        </item>

        <item id="234" name="python">
            <price>3</price>
            <description></description> 
        </item>

        <item id="234" name="scala">
            <price>3</price>
            <description></description> 
        </item>

      </items>

I want output as

 <items>
        <user>
          <id>8788989</id>
         <firstname>test</firstname>
         <lastname>user</lastname>
        </user>
        <info>test xml</info>
        <fromdate><fromdate>
        <todate></todate>
         <group>  
            <item id="123" name="Java">
                <price>1</price>
                <description></description> 
            </item>

            <item id="123" name="Java and XML">
               <price>2</price>
               <description></description> 
            </item>
        </group>

        <group>
           <item id="234" name="python">
              <price>3</price>
              <description></description> 
           </item>

           <item id="234" name="scala">
              <price>3</price>
              <description></description> 
           </item>
       </group>
   </items>

Grouping is done on item/@id


Solution

  • You can group like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="2.0">
    
        <xsl:output indent="yes"/>
    
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="items">
            <items>
                <xsl:apply-templates select="* except item"/>
                <xsl:for-each-group select="item" group-by="@id">
                    <group>
                        <xsl:apply-templates select="../item[@id = current()/@id]"/>
                    </group>
                </xsl:for-each-group>
            </items>
        </xsl:template>
    
    </xsl:stylesheet>
    

    UPDATED ANSWER:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="2.0">
    
        <xsl:output indent="yes"/>
    
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="items">
            <items>
                <xsl:apply-templates select="* except item"/>
                <xsl:for-each-group select="item" group-by="@id">
                    <group>
                        <xsl:apply-templates select="current-group()"/>
                    </group>
                </xsl:for-each-group>
            </items>
        </xsl:template>
    
    </xsl:stylesheet>