Re: [xsl] Why do these xsl:variable declarations give different results?

Subject: Re: [xsl] Why do these xsl:variable declarations give different results?
From: Michael Kay <mike@xxxxxxxxxxxx>
Date: Thu, 20 Dec 2012 23:42:00 +0000
Are we talking XSLT 1.0 or 2.0 here?

The first variable is a set (2.0: sequence) of nodes, being ancestor nodes of the context node. Because of the predicate [position()=last()] this node set/sequence will contain at most one node. The value of $containingChapter/@id is therefore a set (2.0: sequence) of attribute nodes, again containing at most one node. The value is NOT a string, but it can for most purposes be treated as if it were. (An exception would be that boolean() applied to the value behaves differently).

The second variable is a document node (2.0: result tree fragment) containing copies of the ancestor nodes of the context node. As it is a document node and document nodes do not have attributes, $containingChapter/@id will inevitably select nothing (in XSLT 1.0, it's an error, because you can't have a result-tree-fragment on the lhs of the "/" operator).

This difference between variables defined using @select and variables defined using contained instructions is very fundamental and important to understand.

Michael Kay
Saxonica


On 20/12/2012 23:24, Steve Fogel wrote:
Hi, all.

Would appreciate some help. I don't understand how these two definitions of a variable produce different results. This is from the DITA Open Toolkit (OT).
1st alternate definition is without a condition:


<xsl:variable name="containingChapter"
      select="ancestor-or-self::*[contains(@class, ' topic/topic ')][position()=last()]"/>

2nd alternate definition is with a condition, which is me fixing a bug in the (OT).

<xsl:variable name="containingChapter">
     <xsl:choose>
         <xsl:when test="$hasBookParts">  <!-- The book has <part>s -->
             <xsl:copy-of select="ancestor-or-self::*[contains(@class, ' topic/topic ')][last()-1]"/>
         </xsl:when>
         <xsl:otherwise>
             <xsl:copy-of select="ancestor-or-self::*[contains(@class, ' topic/topic ')][last()]"/>
         </xsl:otherwise>
     </xsl:choose>
</xsl:variable>


Both definitions should return a <topic> element with an id attribute. Following the definition is this statement:


<xsl:variable name="id" select="$containingChapter/@id"/>

With the first definition, the value of id is a string, as desired. With the 2nd, it's empty. Bad. Why?

For the 1st definition, the Oxygen debugger gives the value type as "element(1)". For the 2nd, it gives the value type as "document-node(1)". In fact, if you look at the value of the variable in Oxygen's Nodes/Values Set window, for the 1st definition it is:

topic

and for the 2nd, it is:

#document/fragment
    topic

Can someone please advise?

Many thanks!

Steve

Steve Fogel | Information Architect, Oracle Database | 650.506.4914
Oracle Server Technologies Information Development
500 Oracle Parkway | M/S 4op1126 | Redwood Shores, CA 94065

Current Thread