XSLT context, context change

Context Changes

1. XPath context changes.
2. Comparing nodes in XPath
3. Comparing nodes in XPath

1.

XPath context changes.

David Carlisle


> Does the xpath expression  "A/C[position()=2]"   select the 3rd child
> of A, or the second one.

 A/C[position()=2 applies to the current step so it selects the second child of  C here.

If you want to select  C children that are the second child of A then

"A/*[position()=2 and self::C]
[Ednote: the self referred to here is the new context which changes 
  within the predicate to become the child node of A]
  
> (I mean, it requires an xsl:if test="name(*[position()=2])='C']"      )

name() isn't so safe, as it will be wrong if unexpected namespace
prefixes are used.

2.

Comparing nodes in XPath

Wendell Piez


>Ok, but that's not the case when using variable. And i change that to
>
><xsl:value-of
>select="document('connections.xml')/connections/connection[@id=./Conn]"
>/>
>
>but it still doen´t work the way I expected...

What you're missing is the concept of the "context node" for evaluating the expression. The expression "Conn" is short for "child::Conn". The expression "./Conn" is short for "self::node()/child::Conn".

In the example provided, the context node for the expression "@id=Conn" or "@id=./Conn" is the same -- as Mike said, the connection. (The context node for a predicate is each of the nodes being predicated.) Both of these expressions return the same thing when the context is the same. When you use a variable, you have already bound your Conn child to the variable when the expression is evaluated, so the context node is not a concern. Note that where you bind your variable does matter. If you did extra work to do the same thing, and said

<xsl:for-each select="document('connections.xml')/connections/connection">
   <xsl:variable name="conn" select="Conn"/>
   <xsl:if test="@id = $conn">
     <xsl:value-of select="."/>
   </xsl:if>
</xsl:for-each>

it wouldn't work. (Nor would you, an XSLT expert, expect it to.) But this would:

<xsl:variable name="conn" select="Conn"/> <xsl:for-each select="document('connections.xml')/connections/connection">
   <xsl:if test="@id = $conn">
     <xsl:value-of select="."/>
   </xsl:if>
</xsl:for-each>

Right? (And this is the better analogue to what you're doing when your predicate has "@id=$conn")

The short answer: you probably want your predicate to read "@id=current()/Conn", though without seeing the rest of the logic it's impossible to be certain. Or just use the variable: we do this all the time.

3.

Comparing nodes in XPath

Wendell Piez


>Ok, but that's not the case when using variable. And I change that to
>
><xsl:value-of
>select="document('connections.xml')/connections/connection[@id=./Conn]"
>/>
>
>but it still doen´t work the way I expected...

What you're missing is the concept of the "context node" for evaluating the expression.

The expression "Conn" is short for "child::Conn".

The expression "./Conn" is short for "self::node()/child::Conn".

In the example provided, the context node for the expression "@id=Conn" or "@id=./Conn" is the same, the connection. (The context node for a predicate is each of the nodes being predicated.) Both of these expressions return the same thing when the context is the same.

When you use a variable, you have already bound your Conn child to the variable when the expression is evaluated, so the context node is not a concern. Note that where you bind your variable does matter.

If you did extra work to do the same thing, and said

<xsl:for-each select="document('connections.xml')/connections/connection">
   <xsl:variable name="conn" select="Conn"/>
   <xsl:if test="@id = $conn">
     <xsl:value-of select="."/>
   </xsl:if>
</xsl:for-each>

it wouldn't work. (Nor would you, an XSLT expert, expect it to.) But this would:

<xsl:variable name="conn" select="Conn"/> <xsl:for-each select="document('connections.xml')/connections/connection">
   <xsl:if test="@id = $conn">
     <xsl:value-of select="."/>
   </xsl:if>
</xsl:for-each>

Right? (And this is the better analogue to what you're doing when your predicate has "@id=$conn")

The short answer: you probably want your predicate to read "@id=current()/Conn", though without seeing the rest of the logic it's impossible to be certain. Or just use the variable: we do this all the time.