Search code examples
.netxsltxpathxslt-1.0xpath-1.0

Setting a variable conditionally with no cut of ancestor axis


I have xslt/xpath v1.0 stack under .NET.

I want to set a variable $myVar conditionally:

 <xsl:variable name="myVar">
   <xsl:if test="$case ='1'">
     <xsl:copy-of select="$otherVarA/down/the/rabbit/hole"/>
   </xsl:if>
  <xsl:if test="$case ='2'">
     <xsl:copy-of select="$otherVarB/down/the/rabbit/hole"/>
   </xsl:if>
   <xsl:if test="$case ='3'">
     <xsl:copy-of select="$otherVarC/down/the/rabbit/hole"/>
   </xsl:if>        
 </xsl:variable>

Later on there are downward accesses: $myVar/go/deeper but also upward accesses like so $myVar/ancestor::rabbit.

Obviously <xsl:copy-of select="$myVar/down/to/rabbit/hole"/> cuts the path upwards.

How can i set $myVar way in order to access the ancestor axis?

I know that <xsl:variable name=... select=... does not cut upward axis.


Solution

  • The first problem you have got, is that in XSLT 1.0 when you use xsl:copy-of within a variable, the variable itself will be of type "Result Tree Fragment", and so you won't be able to use xpath expressions like $myVar/down/to/rabbit/hole on it. You would need to use the "node-set" extension function to convert it from a Result Tree Fragment to a node-set which you could access the nodes in (See https://www.xml.com/pub/a/2003/07/16/nodeset.html for more details).

    However, this won't solve you main problem, about getting the ancestor. Because you are using xsl:copy-of, you will only be able to access the nodes you have copied, not any of their ancestors in the original XML that weren't copied across.

    I suspect your real case may be more complicated, but given what you have shown in your question, you could define the variable like so:

     <xsl:variable name="myVar"
                   select="$otherVarA[$case ='1']/down/the/rabbit/hole
                           |$otherVarB[$case ='2']/down/the/rabbit/hole
                           |$otherVarC[$case ='3']/down/the/rabbit/hole"/>
    

    This way, you are now referencing the nodes in the original XML, rather than making copies, and so you won't need the node-set function, and the ancestor function can access all ancestors in the original XML.

    This does assume your $otherVarA/B/C variables are references to the original XML, and not result-tree-fragments created with xsl:copy-of too.

    See http://xsltfiddle.liberty-development.net/bwdwrw for a contrived example.