Muenchian Method grouping in XSLT

I owe a deal of thanks for figuring out the Muenchian Method of grouping in XSLT (1.0) to Jeni's article Grouping Using the Muenchian Method. It took, however, a while for me to get my mind around the method completely, and some experimentation, which I'm sharing below.

Specifically I was looking to get a listing of tracks, from my iTunes Playlists to Xml application's output, and group them by album.

For this, all I really need is the track's album and name, which gives a basic layout of the following.

<playlist>
	<track><name>Smile</name><album>Alright, Still</album></track>
	<track><name>Knock &apos;Em Out</name><album>Alright, Still</album></track>
	<!-- Additional tracks removed. -->
</playlist>

 Now the first thing you'll need is a key, that you'll be using to group things by. In this case, since I want to group by album, that will be my key. Immediately before any <xsl:template/> elements I added the following key.

<xsl:key name="tracks-by-album"
	match="track"
	use="album"/>

Here we're grouping the tracks, by the album value.

Now that we have a key, we can, for example, grab just those tracks that are from a certain album.

<xsl:template match="/">
	<ul>
		<xsl:for-each select="key('tracks-by-album', '1492: Conquest of Paradise')">
			<li><xsl:value-of select="name"></xsl:value-of></li>
		</xsl:for-each>
	</ul>
</xsl:template>

This will only output those tracks from the album Vangelis' 1492: Conquest of Paradise.

Stepping back, if I just wanted to grab the first track's album, I could do the following.

<xsl:template match="/">
	<ul>
		<xsl:for-each select="/playlist/track[1]">
			<li><xsl:value-of select="album"/></li>
		</xsl:for-each>
	</ul>
</xsl:template>

That suggests that this code is doing, which will go through every album, and display the first track.

<xsl:template match="/">
	<ul>
		<xsl:for-each select="/playlist/track[count(. | key('tracks-by-album', album)[1]) = 1]">
			<xsl:sort select="album"/>
			<li><xsl:value-of select="album"/>
				<ul>
					<li><xsl:value-of select="name"/></li>
				</ul>
			</li>
		</xsl:for-each>
	</ul>
</xsl:template>

And with a slight tweak, you can loop through and display all the song names from each album.

<xsl:template match="/">
	<ul>
		<xsl:for-each select="/playlist/track[count(. | key('tracks-by-album', album)[1]) = 1]">
			<xsl:sort select="album"/>
			<li>
				<xsl:value-of select="album"/>
				<ul>
					<xsl:for-each select="key('tracks-by-album', album)">
						<li><xsl:value-of select="name"/></li>
					</xsl:for-each>
				</ul>
			</li>
		</xsl:for-each>
	</ul>
</xsl:template>

And after all that discovery, I have exactly what I want; a listing of tracks, grouped by albums. With only slight modification, the grouping can be changed to artist, or any one of any other number of items.

Now if only IE 7+ supported for-each-group, available in XSLT 2.0, this wouldn't be necessary.