One frequent requirement is [bi]grouping[/bi]. Grouping is the act of sorting things into a certain order and then coalescing the data for all things that have the same value for the sort key. For example, if you have data for a library of books, you might use grouping to create a report of books sorted by author, with a pretty visual break between authors and a count of books by each author.
In XML, we sort XML elements and use as the sort key the value of an attribute or subordinate element.
XSLT version 2 will have grouping as a [link http://www.w3.org/TR/xslt20/#grouping]native feature[/link], but most of us are using version 1 XSLT processors. So how do we do grouping?
There are many techniques to achieve grouping, many of which are rather brute-force approaches. However, the Muench method is perhaps the most flexible grouping method to be devised for XSLT version 1. The Muench method is named after
Steve Muench, who developed this method as the Oracle XML Evangelist.
For example, let's use this XML document taken from a recent thread. The Tek-Tips poster wanted to group entries based on the value of
xpos so that he could report all of the
ypos values for each xpos.
[code XML data document]
<?xml version="1.0"?>
<availableSeats>
<Table>
<xpos>8</xpos>
<ypos>2</ypos>
<seat_Status>4</seat_Status>
</Table>
<Table>
<xpos>7</xpos>
<ypos>2</ypos>
<seat_Status>4</seat_Status>
</Table>
<Table>
<xpos>7</xpos>
<ypos>1</ypos>
<seat_Status>4</seat_Status>
</Table>
<Table>
<xpos>9</xpos>
<ypos>3</ypos>
<seat_Status>4</seat_Status>
</Table>
</availableSeats>[/code]
The Muench method:
[code XSLT]
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl

utput method="html"/>
[color blue]<!-- Add an index (key) that allows selection based on the value of xpos -->[/color]
<xsl:key name="X" match="Table" use="xpos"/>
<xsl:template match="/">
<table border="1">
[color blue]<!-- The outer for-each selects the first Table node for every unique xpos value.
In other words, the outer for-each will iterate exactly once for each unique
value of xpos. -->[/color]
<xsl:for-each select="//Table[generate-id(.)=generate-id(key('X', xpos)[1])]">
<xsl:sort select="xpos"/>
<tr><td><strong><xsl:text>XPOS=</xsl:text><xsl:value-of select="xpos"/></strong></td></tr>
[color blue]<!-- The inner for-each iterates over all nodes that match the outer for-each xpos value -->[/color]
<xsl:for-each select="key('X', xpos)">
<xsl:sort select="ypos"/>
<tr><td><xsl:text>YPOS=</xsl:text><xsl:value-of select="ypos"/></td></tr>
</xsl:for-each>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>[/code]
Obviously it is crucial that there be careful matching between the attributes in the
xsl:key element and the
xsl:for-each and
xsl:sort elements.