1

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
  • Good question (+1). See my answer for the only correct solution at present. Commented Sep 15, 2010 at 16:49

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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

4 Comments

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 :)
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! :)
You are right about index typematch. But, I think you need to say something about precedence between // operator and predicates...
@Alejandro: You're of course right. However, I didn't really reflect over that issue since it wasn't part of the original question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.