[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: xsl:sort by a sum()?
It's not so difficult. With using current(), which returns the current node, you can change your sum()-function, so that it works in the <xsl:sort/>. <xsl:template match="/"> <xsl:for-each select="//Fruit[@name and not(@name=preceding::Fruit/@name)]"> <xsl:sort select="sum(//Fruit[@name=current()/@name]/@amount)"/> <xsl:value-of select="@name"/> <xsl:text> : </xsl:text> <xsl:value-of select="sum(//Fruit[@name=current()/@name]/@amount)"/> <br/> </xsl:for-each> </xsl:template> But this makes the code not better. For this 9 lines of code all your XML nodes have to be accessed at least 3 times, because of '//'. Furthermore you are using the preceding-axis. So for every <Fruit> all nodes before this node are accessed again. So a little bit bigger file will increase your processing times extremely. The first step for optimization is to replace the '//' by a more explicit XPATH: '/root/FruitBasket/Fruit' (I added <root> as document element.) So the processor knows where to find the <Fruit>s. Then you can change the template structure instead of using <xsl:for-each>: <xsl:template match="root"> <xsl:apply-templates select="FruitBasket/Fruit[@name and not(@name=preceding::Fruit/@name)]"> <xsl:sort select="sum(/root/FruitBasket/Fruit[@name=current()/@name]/@amount)"/> </xsl:apply-templates> </xsl:template> <xsl:template match="Fruit"> <xsl:value-of select="@name"/> <xsl:text> : </xsl:text> <xsl:value-of select="sum(/root/FruitBasket/Fruit[@name=current()/@name]/@amount)"/> <br/> </xsl:template> Then I replace the preceding-axis by the preceding-sibling-axis, so that only the preceding nodes on the same level are accessed. select="FruitBasket/Fruit[@name and not(@name=../preceding-sibling::FruitBasket/Fruit/@name)]" And now forget this and I show you a complete different method. It's called Muenchian Method and explained at http://www.jenitennison.com/xslt/grouping/muenchian.xml. <!-- building a key-table where the <Fruit>s are 'grouped' by its @name --> <xsl:key name="Fruits" match="Fruit" use="@name"/> <xsl:template match="root"> <!-- apply template on the first node of every 'group' --> <xsl:apply-templates select="FruitBasket/Fruit[count( . | key('Fruits', @name)[1] ) = 1]"> <!-- key('Fruits', @name) returns all <Fruit>s with this @name --> <xsl:sort select="sum(key('Fruits', @name)/@amount)"/> </xsl:apply-templates> </xsl:template> <xsl:template match="Fruit"> <xsl:value-of select="@name"/> <xsl:text> : </xsl:text> <xsl:value-of select="sum(key('Fruits', @name)/@amount)"/> <br/> </xsl:template> This is really easy code, more readable and really time-saving. hope this helps, Joerg > <FruitBasket location="kitchen"> > <Fruit name="Apples" amount="10"/> > <Fruit name="Oranges" amount="20"/> > </FruitBasket> > <FruitBasket location="bedroom"> > <Fruit name="Apples" amount="8"/> > <Fruit name="Oranges" amount="7"/> > </FruitBasket> > > And the following <xsl:for-each>: > > <xsl:for-each select="//Fruit[@name and not(@name=preceding::Fruit/@name)]"> > <xsl:variable name="currentFruit" select="@name"/> > <xsl:value-of select="$currentFruit"><xsl:text> : </xsl:text><xsl:value-of > select="sum(//Fruit[@name=$currentFruit]/@amount)"/><br/> > </xsl:for-each> > > After processing with Saxon 6.5.1 I get this: > Apples: 18 > Oranges: 27 > > Which is fine and dandy, but I've got 25 FruitBaskets with different amount > of fruits each, so I need to sort them by the sum of each Fruit among > FruitBaskets. Is there an Xpath expression that could achieve that? I had > tried many, and also searched in the list, but I couldn't find something > similar to my case. > > Many thanks in advance for the tip. > > Cheers, > > Juan XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|