xmlxsltxslt-1.0muenchian-grouping

XSLT 1.0: Group by attribute and join attribute values


I have the following simplified XML data and I want to group it by the Category ID and see if there's any similar records in the payload, if so I want to join the condition with the found element.

<Items>
   <result>
      <id>11</id>
      <name>ABC</name>
      <condition>new</condition>
   </result>
   <result>
      <id>22</id>
      <name>XYZ</name>
      <condition>new</condition>
   </result>
   <result>
      <id>11</id>
      <name>ABC</name>
      <condition>used</condition>
   </result>
   <result>
      <id>33</id>
      <name>PQR</name>
      <condition>used</condition>
   </result>
</Items>

Expected Result After Grouping:

<Items>
   <result>
      <id>11</id>
      <name>ABC</name>
      <condition>new,used</condition>
   </result>
   <result>
      <id>22</id>
      <name>XYZ</name>
      <condition>new</condition>
   </result>
   <result>
      <id>11</id>
      <name>ABC</name>
      <condition>new,used</condition>
   </result>
   <result>
      <id>33</id>
      <name>PQR</name>
      <condition>used</condition>
   </result>
</Items>

How can I do this in XSLT 1.0 for a large payload where multiple similar records are exists? Is it doable using grouping method?

Current Logic:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sdml="http://selfhtml.org/sdml">
 <xsl:template match="/Items">
    <xsl:copy>
        <xsl:for-each-group select="result" group-by="id"> 
            <records type="{current-grouping-key()}" >
                <xsl:apply-templates select="current-group()" />
            </records>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template> 

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

Current Response:

"@type": "11",
"$": "11ABC<itemdescription>.new11ABC<itemdescription>.used"

Edit1: Response added
Edit2: Typo Edited


Solution

  • As you only want to merge the condition data but keep the separate result elements and also only want to identify the group for a certain id you could use

    <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:key name="result-group" match="result[id = 11]/condition" use="../id"/>
    
      <xsl:template match="result[id = 11]/condition">
          <xsl:copy>
              <xsl:for-each select="key('result-group', ../id)">
                  <xsl:if test="position() > 1">,</xsl:if>
                  <xsl:value-of select="."/>
              </xsl:for-each>
          </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    https://xsltfiddle.liberty-development.net/3MvmXj1

    In XSLT 2 or 3 you can use a variable in the key and template match pattern: https://xsltfiddle.liberty-development.net/a9GPfY