Search code examples
xsltsumxslt-grouping

Sums and Category Grouping and sub Grouping with XSLT


With XSLT, how can I change the following:

<root>
  <element id="1" Team="Rangers" Season="2011" Points="12" />
  <element id="2" Team="Rangers" Season="2012" Points="5" />
  <element id="3" Team="Rangers" Season="2012" Points="3" />
  <element id="4" Team="Astros" Season="2011" Points="12" />
  <element id="5" Team="Astros" Season="2011" Points="9" />
  <element id="5" Team="Astros" Season="2012" Points="2" />
</root>

Into:

<body>
  <h2>Rangers</h2>
  <table>
    <tr><td>2011</td><td>12</td></tr>
    <tr><td>2012</td><td>8</td></tr>
    <tr><td>Total</td><td>20</td></tr>
  <h2>Astros</h2>
  <table>
    <tr><td>2011</td><td>21</td></tr>
    <tr><td>2012</td><td>2</td></tr>
    <tr><td>Total</td><td>1227707</td></tr>
  </table>
</body>

I tried this example but it is missing the extra Muenchian grouping required. Sums and Category Grouping with XSLT Any help would be greatly appreciated!


Solution

  • This should do it:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes" />
      <xsl:key name="kTeam" match="element" use="@Team" />
      <xsl:key name="kTeamYear" match="element" use="concat(@Team, '+', @Season)"/>
    
      <xsl:template match="root">
        <body>
          <xsl:apply-templates select="element[generate-id(.) = 
                                               generate-id(key('kTeam',@Team)[1])]"
                               mode="group"/>
        </body>
      </xsl:template>
    
      <xsl:template match="element" mode="group">
        <xsl:variable name="thisTeam" select="key('kTeam',@Team)" />
        <h2>
          <xsl:value-of select="@Team" />
        </h2>
        <table>
          <xsl:apply-templates 
            select="$thisTeam[generate-id() = 
                               generate-id(key('kTeamYear', 
                                               concat(@Team, '+', @Season))[1]
                                          )]" />
          <tr>      
            <td>
              <xsl:text>Total</xsl:text>
            </td>
            <td>
              <xsl:value-of select="sum($thisTeam/@Points)"/>
            </td>
          </tr>
        </table>
      </xsl:template>
    
      <xsl:template match="element">
        <xsl:variable name="thisSeason"
                      select="key('kTeamYear', concat(@Team, '+', @Season))" />
        <tr>
          <td>
            <xsl:value-of select="@Season" />
          </td>
          <td>
            <xsl:value-of select="sum($thisSeason/@Points)" />
          </td>
        </tr>
      </xsl:template>
    </xsl:stylesheet>
    

    When run on your sample input, this produces:

    <body>
      <h2>Rangers</h2>
      <table>
        <tr>
          <td>2011</td>
          <td>12</td>
        </tr>
        <tr>
          <td>2012</td>
          <td>8</td>
        </tr>
        <tr>
          <td>Total</td>
          <td>20</td>
        </tr>
      </table>
      <h2>Astros</h2>
      <table>
        <tr>
          <td>2011</td>
          <td>21</td>
        </tr>
        <tr>
          <td>2012</td>
          <td>2</td>
        </tr>
        <tr>
          <td>Total</td>
          <td>23</td>
        </tr>
      </table>
    </body>