Now that I look again at this question, I think the real problem is not in iterating, but in using //
.
This is a FAQ:
//p[@class='myclass'][1]
selects every p
element that has a class
attribute with value "myclass"
and that is the first such child of its parent. Therefore this expression may select many p
elements, none of which is really the first such p
element in the document.
When we want to get the first p
element in the document that satisfies the above predicate, one correct expression is:
(//p)[@class='myclass'][1]
Remember: The []
operator has a higher priority (precedence) than the //
abbreviation.
WHanever you need to index the nodes selected by //
, always put the expression to be indexed in brackets.
Here is a demonstration:
<nums>
<a>
<n x="1"/>
<n x="2"/>
<n x="3"/>
<n x="4"/>
</a>
<b>
<n x="5"/>
<n x="6"/>
<n x="7"/>
<n x="8"/>
</b>
</nums>
The XPath expression:
//n[@x mod 2 = 0][1]
selects the following two nodes:
<n x="2" />
<n x="6" />
The XPath expression:
(//n)[@x mod 2 = 0][1]
selects exactly the first n
element in the document with the wanted property:
<n x="2" />
Try this first with the following transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="//n[@x mod 2 = 0][1]"/>
</xsl:template>
</xsl:stylesheet>
and the result is two nodes.
<n x="2" />
<n x="6" />
Now, change the XPath expression as below and try again:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="(//n)[@x mod 2 = 0][1]"/>
</xsl:template>
</xsl:stylesheet>
and the result is what we really wanted -- the first such n
element in the document:
<n x="2" />