Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xslt position always returns 1

Tags:

xslt

xslt-1.0

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?

like image 392
Victor Mukherjee Avatar asked Nov 03 '22 18:11

Victor Mukherjee


1 Answers

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.

like image 97
Ian Roberts Avatar answered Nov 08 '22 05:11

Ian Roberts