Re: [xsl] Multi level Grouping using xslt1.0

Subject: Re: [xsl] Multi level Grouping using xslt1.0
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Mon, 23 Feb 2009 14:13:23 -0500
At 2009-02-23 18:09 +0000, Bafna, Kamlesh wrote:
I am trying to transform a sample input xml given below using xslt 1.0
(I cannot move on to XSLT 2.0 as .NET does not support it and I cannot
use other xslt processors)-

I find the variable-based approach to multi-level grouping is very easy to understand, and it avoids any statistically-possible collisions when creating keys based on concatenation.


The requirement is to group by Company, then by Business, then by
Department & finally the Account.

I hope the example below helps, as it reproduces your desired output precisely.


I am using the following xslt -

In your example you are using keys which have document-wide scope, yet you are trying to group with less-than-document-wide scope. Using variables it is easy to work on only portions of your document.


In my example below I am looking at each subset of the tree in a variable and acting only at the first member in that variable for each unique value in that subset.

. . . . . . . . . . Ken

T:\ftemp>type bafna.xml
<Data>
  <Rows>
    <Row>
      <Company>491</Company>
      <Business>0000</Business>
      <Department>0000</Department>
      <Account>30010</Account>
    </Row>
    <Row>
      <Company>491</Company>
      <Business>0000</Business>
      <Department>0001</Department>
      <Account>30010</Account>
    </Row>
    <Row>
      <Company>498</Company>
      <Business>0000</Business>
      <Department>0000</Department>
      <Account>30010</Account>
    </Row>
    <Row>
      <Company>498</Company>
      <Business>0001</Business>
      <Department>0000</Department>
      <Account>30011</Account>
    </Row>
  </Rows>
</Data>

T:\ftemp>call xslt bafna.xml bafna.xsl bafna.out

T:\ftemp>type bafna.out
<?xml version="1.0" encoding="utf-8"?>
<Message>
   <Company>
      <Code>491</Code>
      <Business>
         <Code>0000</Code>
         <Department>
            <Code>0000</Code>
            <Account>30010</Account>
         </Department>
         <Department>
            <Code>0001</Code>
            <Account>30010</Account>
         </Department>
      </Business>
   </Company>
   <Company>
      <Code>498</Code>
      <Business>
         <Code>0000</Code>
         <Department>
            <Code>0000</Code>
            <Account>30010</Account>
         </Department>
      </Business>
      <Business>
         <Code>0001</Code>
         <Department>
            <Code>0000</Code>
            <Account>30011</Account>
         </Department>
      </Business>
   </Company>
</Message>
T:\ftemp>type bafna.xsl
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                version="1.0">

<xsl:output indent="yes"/>

<xsl:template match="/">
  <xsl:variable name="rows" select="Data/Rows/Row"/>
  <Message>
    <xsl:for-each select="$rows">
      <xsl:if test="generate-id(.)=
                    generate-id($rows[Company=current()/Company][1])">
        <xsl:variable name="company"
                      select="$rows[Company=current()/Company]"/>
        <Company>
          <Code><xsl:value-of select="Company"/></Code>
          <xsl:for-each select="$company">
            <xsl:if test="generate-id(.)=
                        generate-id($company[Business=current()/Business][1])">
              <xsl:variable name="business"
                            select="$company[Business=current()/Business]"/>
              <Business>
                <Code><xsl:value-of select="Business"/></Code>
                <xsl:for-each select="$business">
                  <xsl:if test="generate-id(.)=
                                generate-id($business
                                        [Department=current()/Department][1])">

                    <xsl:variable name="department"
                                  select="$business
                                          [Department=current()/Department]"/>
                    <Department>
                      <Code><xsl:value-of select="Department"/></Code>
                      <xsl:copy-of select="$department/Account"/>
                    </Department>
                  </xsl:if>
                </xsl:for-each>
              </Business>
            </xsl:if>
          </xsl:for-each>
        </Company>
      </xsl:if>
    </xsl:for-each>
  </Message>
</xsl:template>

</xsl:stylesheet>

T:\ftemp>rem Done!



--
XQuery/XSLT training in Prague, CZ 2009-03 http://www.xmlprague.cz
Training tools: Comprehensive interactive XSLT/XPath 1.0/2.0 video
Video lesson:    http://www.youtube.com/watch?v=PrNjJCh7Ppg&fmt=18
Video overview:  http://www.youtube.com/watch?v=VTiodiij6gE&fmt=18
G. Ken Holman                 mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/s/
Male Cancer Awareness Nov'07  http://www.CraneSoftwrights.com/s/bc
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal

Current Thread