RE: [xsl] Xpath and for-each looping

Subject: RE: [xsl] Xpath and for-each looping
From: "Passin, Tom" <tpassin@xxxxxxxxxxxx>
Date: Fri, 16 May 2003 17:39:28 -0400
[Alan Gardner]
>...
> How do I write it to loop through just the item nodes once 
> and sort them by
> date?
> 
 Well, it is better not to "loop" through them and test each one at all,
but rather to select just the ones you want in the first place.  You
actually have several issues to solve -

1) How to sort them since xslt will not be able to sort on the date as
is (it does not understand date formats).

2) How to get just the last five items by date.

If you would like to display the items __most recent first__ then it is
easy to accomplish both of those goals together.

First, how to sort? I used an old database trick.  The sort key is a
unique combination of month, day, and year like this -

key = day + 50 * month + (2000 + year)

(you may have to tinker with this depending on your date format and
whether it could go back earlier than the year 2000 and whether you
really will be using 2-digit dates).  You could also sort by the three
fields by using three separate xsl:sort statements, one for each field
in the data, and avoid the arithmetic games.

Next, you want to select items, and it is easier to read the code if you
make a variable to hold them.  You select the items in an
xsl:apply-templates instruction.  You ask for all those items whose
position is less than 5, which will be the top 4 in reverse data order,
and you have your results.   You never have to "loop through" and you
never have to test each item because you have selected just the right
items.

To test it, I changed the items in your example a bit so that they were
for different dates (and I just used the last two instead of the last
five items, since your example only included three items).

<xsl:stylesheet version="1.0" 
	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:variable name='items' select='/fxml/rdf:RDF/item'/>

<xsl:template match="/fxml">
<results>
   <xsl:apply-templates select='$items[5 > position()]'>
      <xsl:sort select='50*substring(date,1,2) + 
               number(substring(date,4,2)) +2000 +  
               number(substring(date,7,2))' 
               order='descending'/>
   </xsl:apply-templates>
</results>
</xsl:template>

<xsl:template match='item'>
	<item><xsl:value-of select='title'/></item>
</xsl:template>

</xsl:stylesheet>

If you want forward ascending order, the predicate is a bit more
complicated but not bad, something like position() > (count($items) -5).

Cheers,

Tom P

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread