[XSL-LIST Mailing List Archive Home]
[By Thread]
[By Date]
RE: [xsl] grouping/position problem
Subject: RE: [xsl] grouping/position problem From: "Michael Kay" <mike@xxxxxxxxxxxx> Date: Sat, 23 Apr 2005 15:32:42 +0100 |
On entry to xsl:for-each-group, the context item (.) is the first item in the group, by definition. So the expression (. is current-group()[1]) will always be true. Changing "." to current() doesn't help because at the outermost level of an XPath expression, current() is the same as ".". I'm having to go back to your original post now to see what you're actually trying to do. Let's start by looking at your existing code. I've changed it so that the XSLT code uses the element and attribute names that actually appear in the XML source, please check I've got this right: <list> <item author="five" year="2001"/> <item author="three" year="2003"/> <item author="four" year="2002"/> <item author="two" year="1998"/> <item author="one" year="2005"/> <item author="two" year="2000"/> <item author="four" year="1999"/> </list> <xsl:template match="list" mode="sort_author-year"> <xsl:for-each-group select="item" group-by="@author"> <xsl:sort select="current-grouping-key()"/> <xsl:variable name="author-position" select="position()"/> <xsl:variable name="shorten-author" as="xs:boolean" select="$author-position > 1" /> <xsl:for-each-group select="current-group()" group-by="@year"> <xsl:sort select="current-grouping-key()" /> <xsl:variable name="year"> <xsl:value-of select="current-grouping-key()"/> <xsl:if test="last() > 1"> <xsl:number value="position()" format="a"/> </xsl:if> </xsl:variable> <xsl:for-each select="current-group()"> <xsl:apply-templates select="."> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="shorten-author" select="$shorten-author"/> </xsl:apply-templates> </xsl:for-each> </xsl:for-each-group> </xsl:for-each-group> </xsl:template> Within xsl:for-each-group, you are processing a group of items. "." refers to the first item in the group, position() refers to the position of this group within the sequence of groups (it's 1 for the first group, 2 for the second, and so on). last() is the number of groups. So this code: <xsl:variable name="author-position" select="position()"/> <xsl:variable name="shorten-author" as="xs:boolean" select="$author-position > 1" /> sets $shorten-author to true if you're processing the second or subsequent group of same-author items. I don't think this is what you intended - you wanted it true for the second and subsequent items within each same-author group. (You're only executing this code once for each group of same-author items, so position() can't vary from one item in this group to another!) The position of an author within a group of same-author items is given by the value of position() in the inner loop, that is, the loop in which you iterate over the same-author items. Your data doesn't actually have an example of two items in which the author and year are the same, nor do you give the required output, so I'm now having to make guesses. Lets say you have: <list> <item author="one" year="2001"/> <item author="one" year="2001"/> <item author="one" year="2002"/> </list> Do you want $shorten-author to be true only for the second item, or for the third one as well? I'm assuming only for the second: that is, you're concerned with the position within the group of same-author-same-year items. This is simply the value of position() within the innermost group. This suggests that the code you want is: <xsl:template match="list" mode="sort_author-year"> <xsl:for-each-group select="item" group-by="@author"> <xsl:sort select="current-grouping-key()"/> <xsl:for-each-group select="current-group()" group-by="@year"> <xsl:sort select="current-grouping-key()" /> <xsl:variable name="year"> <xsl:value-of select="current-grouping-key()"/> <xsl:if test="last() > 1"> <xsl:number value="position()" format="a"/> </xsl:if> </xsl:variable> <xsl:for-each select="current-group()"> <xsl:variable name="author-position" select="position()"/> <xsl:variable name="shorten-author" as="xs:boolean" select="$author-position > 1" /> <xsl:apply-templates select="."> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="shorten-author" select="$shorten-author"/> </xsl:apply-templates> </xsl:for-each> </xsl:for-each-group> </xsl:for-each-group> </xsl:template> You could equally well compute position() within the match="item" template rule, in which case you could change the code <xsl:for-each select="current-group()"> <xsl:variable name="author-position" select="position()"/> <xsl:variable name="shorten-author" as="xs:boolean" select="$author-position > 1" /> <xsl:apply-templates select="."> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="shorten-author" select="$shorten-author"/> </xsl:apply-templates> </xsl:for-each> to read <xsl:apply-templates select="current-group()"> <xsl:with-param name="year" select="$year"/> </xsl:apply-templates> If my assumption is wrong, and you want $shorten-author to be true for subsequent items with the same author whether or not the year is the same, you need to move the variable into the code that processes all the same-author items and groups them by year; you will also need to sort by year at this level so you get the position in the sorted order. Michael Kay http://www.saxonica.com/ P.S. I thought you solved this problem months ago? > -----Original Message----- > From: Bruce D'Arcus [mailto:bdarcus@xxxxxxxxx] > Sent: 23 April 2005 11:10 > To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx > Subject: Re: [xsl] grouping/position problem > > > On Apr 23, 2005, at 4:48 AM, Michael Kay wrote: > > > Assuming $NiQ is a member of current-group(), then you only need to > > test > > "$NiQ is not the first in the group", because that implies > that there > > is > > more than one node in the group. So: > > > > test="not($NiQ is current-group()[1]) > > Thanks. > > But now a dumb question: how do I specify $NiQ? What the expression > (or other code) that allows me to define "the member of a > current-group()"? Here's the relevant bit, but I've got it wrong: > > <xsl:template match="mods:modsCollection" mode="sort_author-year"> > <xsl:variable name="bibrefs" select="mods:mods"/> > <xsl:for-each-group select="$bibrefs" > group-by="bib:grouping-key(.)"> > <xsl:sort select="current-grouping-key()"/> > <xsl:variable name="author-shorten" select="test="not(. is > current-group()[1])"/> > <!-- next group --> > > Bruce
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] grouping/position problem, Bruce D'Arcus | Thread | Re: [xsl] grouping/position problem, Bruce D'Arcus |
Re: [xsl] How to URL encode?, Brian Dunning | Date | RE: [xsl] How to URL encode?, Michael Kay |
Month |