Search code examples
xmlxsltxslkeyxsl-grouping

XSLT Key Grouping for Child Nodes


<root>
   <Entry>
      <ID>1</ID>
      <Details>
         <Code>A1</Code>
         <Value>1000</Value>
      </Details>

      <Details>
         <Code>A2</Code>
         <Value>2000</Value>
      </Details>
   </Entry>

   <Entry>
      <ID>2</ID>
      <Details>
         <Code>B1</Code>
         <Value>1500</Value>
      </Details>

      <Details>
         <Code>B2</Code>
         <Value>2500</Value>
      </Details>

      <Details>
         <Code>A3</Code>
         <Value>3000</Value>
      </Details>
   </Entry>

</root>

I have this Input XML. For each <Entry>, I am looking to group the <Details> nodes (which are the Child nodes of Entry) and eventually take the sum of the <Value> node values by following Code Groupings are as follows:

  1. Codes A1, A2 and A3 should be grouped together (say 'A')
  2. Codes B1, B2 and B3 should be grouped together (say 'B')

[Note: The Codes are just for example and the actual codes are entirely different, so a substring solution wont work, please do not consider these codes literally]

The Output would look like:

<Output>
    <Output-Line>
       <ID> 1 </ID>
      <Code-group> A </Code-group>
      <Sum> 3000 </Sum>

      <Code-group> B </Code-group>
      <Sum/>
    </Output-Line>

   <Output-Line>
       <ID> 2 </ID>
      <Code-group> A </Code-group>
      <Sum> 3000 </Sum>

      <Code-group> B </Code-group>
      <Sum> 4000 </Sum>
    </Output-Line>
</Output>

The problem that I am facing currently is that the <xsl:key> element should be declared at the top and not at individual Entry level in a for-each loop. Therefore I am not able to form a proper key with the match and use expression parameters. Any help appreciated.

Thanks in Advance!


Solution

  • Assuming this is just another variation on your previous question, all you need to do is add another argument to the key() function call in order to restrict it to the current Entry:

    XSLT 2.0

    <xsl:stylesheet version="2.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="entry" match="Details" use="Code"/>
    
    <xsl:template match="/root">
        <Output>
            <xsl:for-each select="Entry">
                <Output-Line>
                    <xsl:copy-of select="ID"/>
                    <Code-group> A </Code-group>
                    <Sum>
                        <xsl:value-of select="sum(key('entry', ('A1', 'A2', 'A3'), .)/Value)" />
                    </Sum>
                    <Code-group> B </Code-group>
                    <Sum>
                        <xsl:value-of select="sum(key('entry', ('B1', 'B2', 'B3'), .)/Value)" />
                    </Sum>
                </Output-Line>
            </xsl:for-each>
        </Output>
    </xsl:template>
    
    </xsl:stylesheet>