tags:

views:

38

answers:

2

Hi,

I have a recursive template so that I can update a count. In the template, I want to be able to use the current count to be able to access the node whose index is the current count.

<!-- in the template -->

<xsl:param name="i"/>
<xsl:param name="count"/>      

<NewNode>
    <xsl:value-of select="//ACommonElementInTheDocument[$i]/MyElement"/> : <xsl:value-of select="$i"/>
</NewNode>

I get $i printed out correctly, as expected, but I'm not able to reference the element, although this works perfectly when I use XMLSpy to test the XPath.

Could anyone point out the glaring mistake I'm making please?...

Many thanks

+1  A: 

I'm not sure how you have declared the parameter. But my guess is that this is a type casting problem. What happens if you try:

//ACommonElementInTheDocument[number($i)]/MyElement

Or in XSLT 2.0 you could also use one of the XML Schema types:

//ACommonElementInTheDocument[xs:integer($i)]/MyElement
Per T
The simple answer to your question about casting, would be, it works. Isn't it already a number though? Many thanks for your incredibly quick answer :)
Paul
As I said, it depends a bit on how you have declared or send the parameter to the template to begin with. If you make a new question with some more of your code we could probably explain it better for you. Happy it worked! :)
Per T
@Per T: You are right about index typematch. But, I think you need to say something about precedence between `//` operator and predicates...
Alejandro
@Alejandro: You're of course right. However, I didn't really reflect over that issue since it wasn't part of the original question.
Per T
+4  A: 

In XSLT 1.0/XPath 1.0 variables/parameters are not explicitly typed.

Therefore, in XSLT 1.0 the solution is to use:

someExpression[position() = $i]

or

someExpression[number($i)]

In XSLT 2.0 it is best to define the parameter as xs:integer:

<xsl:param name="i" as="xs:integer"/>

then using

someExpression[$i]

produces the wanted result.

Do note, however, that an expression like:

//ACommonElementInTheDocument[1]

doesn't select the first element in the document that is named ACommonElementInTheDocument.

This expression selects every ACommonElementInTheDocument element that is the first ACommonElementInTheDocument child of its parent -- therefore the above expression generally may return many elements and it is possible that none of them would be the first ACommonElementInTheDocument in the document.

This is why the solution of @Per-T is most probably incorrect -- both in XSLT 1.0 and in XSLT 2.0.

Instead of:

//ACommonElementInTheDocument[number($i)]/MyElement 

use

(//ACommonElementInTheDocument)[number($i)]/MyElement 

Remember: The [] operator binds stronger (has a higher precedence) than the // abbreviation.

Dimitre Novatchev
@Dimitre: +1 Very good explanation!
Alejandro
+1 Good explanation as always!
Per T
+1 I learned something new. Or relearned something old. :-)
LarsH