tags:

views:

201

answers:

3

I need to render a specified number of elements from an XML source, where the elements "DueDate" is not exeeded. Here is an example of the xml:

<Items>
  <Item>
    <Title>Title 1</Title>
    <DueDate>01-02-2008</DueDate>
  </Item>
  <Item>
    <Title>Title 2</Title>
    <DueDate>01-02-2009</DueDate>
  </Item>
  <Item>
    <Title>Title 3</Title>
    <DueDate>01-02-2010</DueDate>
  </Item>
  <Item>
    <Title>Title 4</Title>
    <DueDate>01-02-2011</DueDate>
  </Item>
  <Item>
    <Title>Title 5</Title>
    <DueDate>01-02-2012</DueDate>
  </Item>
  <Item>
    <Title>Title 6</Title>
    <DueDate>01-02-2013</DueDate>
  </Item>
</Items>

The number of elements to display and the current date are passed to the XSLT as paramaters. Is it possible to count the number of rendered elements in a for-each loop in Xslt? Or is there a better approach?

An example could be that the limit was set to 3 elements. In this example I would expect to see the following results: "Title 3", "Title 4" and "Title 5".

+1  A: 

Try nesting this inside a standard xsl for-each where n in your case is 3:

<xsl:if test="position() &lt; n">

But if you also want to check the date then you will need nest another if and create dates in the format yyyyMMdd which can be numerically compared like this:

<xsl:variable name="secondDate" select="concat(substring(submissionDeadline, 1,4),substring(submissionDeadline, 6,2),substring(submissionDeadline, 9,2))"/>

<xsl:if test="$firstDate &gt; $secondDate">
markoo
+3  A: 

You can do something like this. Make it into a template you can call with paramters:

<xsl:template match="/">
<xsl:variable name="count" select="3"/>

<xsl:for-each select="Items/Item">
 <xsl:if test="position() &lt; $count">
  <xsl:value-of select="Title"/> - <xsl:value-of select="DueDate"/>
 </xsl:if>
</xsl:for-each>

Tommy
But this will not remove items where the "DueDate" is greater than today? It will just give me the first three elements! If I include an if statement to check date, only the thrid (position() == 3) "valid" element is shown.
A: 

The main problem is that your input XML does not conform to the useful 'yyyy-mm-dd' format. This makes sorting/filtering these items a pain in the ass behind.

If I understand you correctly, you need to

  • filter on due date first
  • apply a maximum to the output after that

The XPath for selecting all <Item>s up to a certain maximum due date would go like this:

Item[
  substring-before(DueDate, '-') 
  &lt;= 
  substring-before($MaxDueDate, '-')

  and

  substring-before(substring-after(DueDate, '-'), '-')
  &lt;= 
  substring-before(substring-after($MaxDueDate, '-'), '-')

  and 

  substring-after(substring-after(DueDate, '-'), '-')
  &lt;= 
  substring-after(substring-after($MaxDueDate, '-'), '-')
][
  position() &lt;= $MaxCount
]

Now compare that to the trivial way, if you had 'yyyy-mm-dd' dates:

Item[
  DueDate &lt;= $MaxDueDate
][
  position() &lt;= $MaxCount
]

So, to copy only these elements, you would go:

<xsl:template match="Items">
  <xsl:copy>
    <xsl:copy-of select="
      { the expression I gave above }
    " />
  </xsl:copy>
</xsl:template>

For parameter values of '01-02-2012' and 4, respectively, I get:

<Items>
  <Item>
    <Title>Title 1</Title>
    <DueDate>01-02-2008</DueDate>
  </Item>
  <Item>
    <Title>Title 2</Title>
    <DueDate>01-02-2009</DueDate>
  </Item>
  <Item>
    <Title>Title 3</Title>
    <DueDate>01-02-2010</DueDate>
  </Item>
  <Item>
    <Title>Title 4</Title>
    <DueDate>01-02-2011</DueDate>
  </Item>
</Items>
Tomalak