Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 631
  • Last Modified:

Problem with xsl:sort and apply-templates


I simply need to select the most recent list of item (by date). The XML contains
multiple lists, in any order and will contain "future" items. The dates are converted
to UTC basic format (CCYYMMDD) so they can be treated as ordinary numbers. So the
logic is essentially, sort the list by "date", then select the last() item
where date is less than "now".

I can only get it to work if I do it in two steps (See Method #2 below). But this
means that each list node needs to be tested. Does this create any additional
overhead? Can it be done in one step?

<schedule>
   <list date="20041231">
      <item title="Ancient #1"/>
      <item title="Ancient #2"/>
      <item title="Ancient #3"/>
   </list>

   <list date="20050515">
      <item title="Future #1"/>
      <item title="Future #2"/>
      <item title="Future #3"/>
   </list>
   
   <list date="20050507">
      <item title="Current #1"/>
      <item title="Current #2"/>
      <item title="Current #3"/>
   </list>

   <list date="20050505">
      <item title="Recent #1"/>
      <item title="Recent #2"/>
      <item title="Recent #3"/>
   </list>
</schedule>


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:param name="now">20050511</xsl:param>

   <xsl:template match="//schedule">

      Method #1 Doesn't work because the sort happens after the select<br/>
      <xsl:apply-templates select="list[@date &lt; $now][last()]/item">
         <xsl:sort select="@date"/>
      </xsl:apply-templates>

      <hr/>

      Method #2 Works: but it needs two steps. Can it be done together?<br/>
      <xsl:apply-templates select="list[@date &lt; $now]">
         <xsl:sort select="@date"/>
      </xsl:apply-templates>

   </xsl:template>

   <xsl:template match="list">
      Test if current node is last().
      <xsl:if test="position() = last()">
         <xsl:apply-templates select="item"/>
      </xsl:if>
   </xsl:template>

   <xsl:template match="item">
      <xsl:value-of select="@title"/><br/>
   </xsl:template>

</xsl:stylesheet>
0
cklanac
Asked:
cklanac
1 Solution
 
b1xml2Commented:
it cannot be done in one single step because you have to
1. Get the resulting node-set (collection of nodes)
2. Sort the node-set
3. Retrieve the last position.

<xsl:for-each select="list[@date &lt; $now][last()]/item">
<xsl:sort select="@date"/>
<xsl:if test="position() = last()">
<xsl:apply-templates select="." />
</xsl:if>
</xsl:for-each>

Your attempt
<xsl:apply-templates select="list[@date &lt; $now][last()]/item">
simply means that you are retrieving the last node from the nodeset against the document heirarchy. Typically this would mean that the last node in the tree that matches the criteria, not sorted of course.
0
 
cklanacAuthor Commented:
Thanks for the info...
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Tackle projects and never again get stuck behind a technical roadblock.
Join Now