How to sort and then select one item

I use XSLT to get data from the feed. I am currently using this block of code , which simply selects the first item from the feed. I changed it a bit, so it applies to this XML sample.

<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:template match="/"> <xsl:value-of select="catalog/book/author"/> </xsl:template> </xsl:stylesheet> 

I want to sort xml by price, and then select the author associated with the best-selling book. I have tried all kinds of things, but I cannot figure it out.

The current output is Gambardella, Matthew, but I need it to be Galos, Mike.

+4
source share
3 answers

you can specify <xsl:sort> inside apply templates, for example:

 <xsl:template match="/"> <html> <body> <xsl:apply-templates select="/catalog/book"> <xsl:sort select="price" order="descending" data-type="number"/> </xsl:apply-templates> </body> </html> </xsl:template> 

and then in your small book template use position() to filter only the first book node

 <xsl:template match="book"> <xsl:if test="position() = 1"> <xsl:value-of select="author"/> <br/> <xsl:value-of select="price"/> </xsl:if> </xsl:template> 
+1
source

I want to sort xml by price, and then select the author associated with the best-selling book.

FWIW, you can do this with pure XPath too.

 /catalog/book[not(price < /catalog/book/price)]/author 

(The predicate reads: "Choose any <book> whose <price> not lower than any book.")

This will select <author>Galos, Mike</author> in the XML sample .

Notes

  • No book is selected in this expression with the highest price, but all the books with the highest value (i.e. she would choose two books if there were two with the same price). Use

     /catalog/book[not(price < /catalog/book/price)][1]/author 

    to select exactly one suitable book (the first one in the order of the document will be selected).

  • XPath automatically forces both operands to the less / greater than (or equal to) comparison types, numbers . As long as the <price> values ​​are directly converted to numbers, this expression will succeed.

  • It must be the reverse logic ("not (less than any)"), because the opposite ("more than any") can never be true (whereas "more or equal to any" will always be true).

  • The time complexity of the operations nodeset1[expression < nodeset2] :
    β†’ O (count (nodeset1) & times; count (nodeset2)).
    In the above case, nodeset1 and nodeset2 identical, so the effective time complexity is:
    β†’ O (nΒ²).
    In other words, this is not the most efficient way to solve this problem (I would say that <xsl:apply-templates> with <xsl:sort> is), but on the other hand, it is a one-line one that can be fast enough for you.

+3
source

you need and use the position function only to return only the first:

 <xsl:template match="/"> <html> <body> <xsl:apply-templates select="/catalog/book"> <xsl:sort select="price" order="descending" data-type="number"/> </xsl:apply-templates> </body> </html> </xsl:template> <xsl:template match="book"> <xsl:if test="position()=first()"> <xsl:value-of select="author"/> </xsl:if> </xsl:template> 
0
source

Source: https://habr.com/ru/post/1444366/


All Articles