[xsl] position() in xsl:for-each

Subject: [xsl] position() in xsl:for-each
From: Vidar Ramdal <vramdal@xxxxxxxxx>
Date: Fri, 9 Jul 2004 10:32:02 +0200
I have a very simple XML tree like this:

<objects>
  <object name="name1" type="type1">data1</object>
  <object name="name2" type="type1">data2</object>
  <object name="name3" type="type1">data3</object>
  <object name="name4" type="type1">data4</object>
  <object name="name5" type="type2">data5</object>
 </objects>

Now, I want to exclude the "type2" object, and transform this to a
HTML table, displaying 2 <object>s per row:

<table>
  <tr>
    <td>name1</td><td>data1</td><td>name2</td><td>data2</td>
    <td>name3</td><td>data3</td><td>name4</td><td>data4</td>
  </tr>
</table>

So I've written this template:

<xsl:template match="objects">
  <table>
     <xsl:for-each select="object[@type='type1'][position() mod 2 = 1]">
        <td><xsl:apply-templates select="."/></td>
        <td><xsl:apply-templates select="following-sibling::*[1]"/></td>
     </xsl:for-each>
  </table>
</xsl:template>

This gives the desired result, but today I started wondering *why* it worked :) 

What puzzles me is that following-sibling::*[1] selects the next
element in the input tree, and not in the nodeset I select in the
for-each.

That is, why does following-sibling::*[1] give me <object
name="name2"> and not <object name="name3"> ?

It seems to me that it works as if I had not specified [position() mod
2 = 1], but honoring [@type='type1'] (as it does not output the
<object type="type2">)

I've browsed the XSLT spec, but couldn't find anything that explains
this behaviour. Anyone?

-- 
Vidar S. Ramdal

Current Thread