[XSL-LIST Mailing List Archive Home]
[By Thread]
[By Date]
Re: [xsl] XSLT conditional sorting problem
Subject: Re: [xsl] XSLT conditional sorting problem From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx> Date: Tue, 11 Nov 2003 09:06:44 +0000 |
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 {@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
Current Thread |
---|
<- Previous | Index | Next -> |
---|---|---|
[xsl] XSLT conditional sorting prob, thei | Thread | RE: [xsl] XSLT conditional sorting , thei |
[xsl] XSLT conditional sorting prob, thei | Date | RE: [xsl] maximum depth of nested t, Andy Verbunt |
Month |
Keywords