XSLT - Grouping with Keys

Since XSLT 1.0 doesn’t have built-in grouping, we use the Muenchian Method, which relies on <xsl:key>.

 Grouping with Keys (Muenchian Method)

Steps

  1. Define a key to index nodes by the grouping property.

  2. Select only the first occurrence of each group (using generate-id()).

  3. Inside that, use the key() function to fetch all nodes that belong to that group.


Example XML

<library>
    <book>
        <title>XML Basics</title>
        <author>Alice</author>
    </book>
    <book>
        <title>XSLT in Action</title>
        <author>Bob</author>
    </book>
    <book>
        <title>Advanced XML</title>
        <author>Alice</author>
    </book>
    <book>
        <title>XPath Mastery</title>
        <author>Bob</author>
    </book>
</library>

XSLT with Grouping

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <!-- 1. Define a key: group books by author -->
    <xsl:key name="booksByAuthor" match="book" use="author"/>

    <xsl:template match="/">
        <html>
            <body>
                <h2>Books Grouped by Author</h2>
                <xsl:for-each 
                    select="library/book[generate-id() = generate-id(key('booksByAuthor', author)[1])]">
                    
                    <!-- 2. Group heading: the author -->
                    <h3><xsl:value-of select="author"/></h3>
                    <ul>
                        <!-- 3. Get all books by this author -->
                        <xsl:for-each select="key('booksByAuthor', author)">
                            <li><xsl:value-of select="title"/></li>
                        </xsl:for-each>
                    </ul>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

Output

<html>
  <body>
    <h2>Books Grouped by Author</h2>

    <h3>Alice</h3>
    <ul>
      <li>XML Basics</li>
      <li>Advanced XML</li>
    </ul>

    <h3>Bob</h3>
    <ul>
      <li>XSLT in Action</li>
      <li>XPath Mastery</li>
    </ul>
  </body>
</html>

How it Works

  1. xsl:key creates an index mapping authors → their books.

  2. key('booksByAuthor', author) retrieves all books for a given author.

  3. [generate-id() = generate-id(key('booksByAuthor', author)[1])] ensures we only pick the first book of each author (so each group is processed once).