I have the following template:
<xsl:template match="/">
<Envelopes>
<xsl:variable name="var1" select="ExtObj:GetXml()"/>
<xsl:apply-templates select="$var1/*"/>
</Envelopes>
</xsl:template>
<xsl:template match='xyz/abc'>
<xsl:variable name="pos" select="position()"/>
</xsl:template>
Now $var1
has elements which matches the second template, but the $pos
always is set at 1. How can I get the position of the match?
The position()
function is inherently context-sensitive - it gives you the position of the current node within the set of nodes selected by the apply-templates
that caused this template to fire. So it depends on exactly what the $var1
variable contains. If $var1
is a node set containing xyz
elements, each of which has a single abc
child, then $var1/*
will select all the abc
elements in one go:
<xyz> <!-- $var1 -->
<abc/> <!-- $var1/* -->
</xyz>
<xyz> <!-- $var1 -->
<abc/> <!-- $var1/* -->
</xyz>
(the whitespace text nodes and comments are for clarification only, assume the real XML tree contains only the element nodes) and you'll get the position()
values you expect.
But if $var1
is a single root node in the XPath data model (e.g. a document fragment) that has the xyz
elements as its children, then $var1/*
will select the xyz
elements, not the abc
ones.
<!-- $var1 (the root node) -->
<xyz> <!-- $var1/* -->
<abc/>
</xyz>
<xyz> <!-- $var1/* -->
<abc/>
</xyz>
Now when you apply templates to these the implicit default template will match them, and for each one it will recursively call apply-templates
on that node's children (the single abc
element). So now position()
will give you the position of the abc
within the set of its parent's children, which will always be 1.
If this is what's happening, then the easiest fix is to say
<xsl:apply-templates select="$var1/*/*"/>
to select all the abc
elements in one go.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With