Hi Ned,
When I encounter an album by various artists, I'd like to handle it
as below, but was unable to figure out how to correctly do this:
"Various Artists" - Album_1
Artist - Song_1
Artist - Song-2
...
You're using Muenchian Grouping to group the <song> elements based on
their album, and applying templates to the first <song> in a
particular album in 'albums' mode.
Within that template, you can (and do) get hold of all the songs on
the album using:
key('albums', @album)
Hold that in a variable called songs:
<xsl:variable name="songs" select="key('albums', @album)" />
Now, if it's true that an @artist attribute of one of the <song>
elements in $songs is *not*equal*to* another @artist attribute of one
of the <song> elements in $songs, then you have an album by various
artists. You can test this with:
$songs/@artist != $songs/@artist
Note that the != comparison uses "existential semantics" -- it returns
true if any of the comparisons between the artist attributes returns
true, so if *any* artist is not the same as *any* other artist.
So you can use this test to determine whether to put "Various Artists"
or use the name of the only artist:
<xsl:choose>
<xsl:when test="$songs/@artist != $songs/@artist">
<xsl:text>Various Artists</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@artist" />
</xsl:otherwise>
</xsl:choose>
You can also use the test to determine a mode in which to apply
templates to the songs, or to pass a parameter into a template,
whichever suits you better. For example:
<ul title="Songs">
<xsl:apply-templates select="$songs" mode="songs">
<xsl:sort select="@tracknr" data-type="number" />
<xsl:with-param name="show-artist"
select="$songs/@artist != $songs/@artist" />
</xsl:apply-templates>
</ul>
with:
<xsl:template match="song" mode="songs">
<xsl:param name="show-artist" select="false()" />
<li title="(Track {(_at_)tracknr})">
<xsl:if test="$show-artist">
<xsl:value-of select="@artist"/>
<xsl:text> - </xsl:text>
</xsl:if>
<xsl:value-of select="@title"/>
</li>
</xsl:template>
One additional thing, if anyone's feeling particularly intelligent
and helpful - I would be interested to see how I'd sort my XML data
into nested lists on both artist and album, as such:
Artist_1
Album_1
Song_1
Song_2
...
Album_2
...
Artist_2
...
To do that, you need two levels of Muenchian Grouping. Define the two
keys, one that indexes the <song> elements by artist:
<xsl:key name="songs-by-artist" match="song" use="@artist" />
and another that indexes the <song> elements by artist and album by
concatenating the two values:
<xsl:key name="songs-by-artist-and-album" match="song"
select="concat(@artist, ' - ', @album)" />
At the first level, you want to apply templates to the first <song> by
a particular artist, in 'artists' mode:
<xsl:template match="music">
<ul title="Songs">
<xsl:apply-templates mode="artists"
select="song[generate-id(.) =
generate-id(key('songs-by-artist',@artist)[1])]" />
</ul>
</xsl:template>
The template for 'artists' mode needs to give the artist, and then
apply templates to the first <song> element with that artist on each
particular album, in 'albums' mode, using the second key:
<xsl:template match="song" mode="artists">
<li>
<xsl:value-of select="@artist" />
<xsl:variable name="songs"
select="key('songs-by-artist', @artist)" />
<ul title="Songs">
<xsl:apply-templates mode="albums"
select="$songs[generate-id(.) =
generate-id(key('songs-by-artist-and-album',
concat(@artist, ' - ', @album))[1])]" />
</ul>
</li>
</xsl:template>
The template for 'albums' mode is similar to what you have already,
except that it uses the 'songs-by-artist-and-album' key. A simplified
version would be:
<xsl:template match="song" mode="albums">
<li>
<xsl:value-of select="@album" />
<xsl:variable name="songs"
select="key('songs-by-artist-and-album',
concat(@artist, ' - ', @album))" />
<ul title="Songs">
<xsl:apply-templates select="$songs" mode="songs">
<xsl:sort select="@tracknr" data-type="number" />
</xsl:apply-templates>
</ul>
</li>
</xsl:template>
I don't know how you want to combine this two-level grouping with the
special handling of albums by "Various Artists" -- whether you want
the album to be listed under the artist or you want a special "Various
Artists" category -- but hopefully you should be able to work out how
to do it. If you need more help, let us know.
Cheers,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list