smilingthax
smilingthax

Reputation: 5754

xslt variable strangeness

Can anyone explain this to me? (using latest libxslt):

 <a><xsl:copy-of select="(@attrib|exsl:node-set(0))"/></a>
 <b><xsl:copy-of select="(@attrib|exsl:node-set(0))[position()=1]"/></b>

 <x><xsl:copy-of select="(@attrib|exsl:node-set(0))[1]"/></x>
 <xsl:variable name="value" select="@attrib"/>
 <y><xsl:copy-of select="($value|exsl:node-set(0))[1]"/></y>

Result (for @attrib = 1 at current node):

 <a attrib="1">0</a>
 <b attrib="1"/>

 <x>0</x>
 <y attrib="1"/>

<a> and <b> show expected behavior.
<x> is IMHO incorrect.
But why does putting @attrib into a variable "fix" it for <y>?

BTW: Everything is correct when @attrib is not present. The copy-of used here is for debugging; original usage converts the XPath result to a number, and a missing attribute shall not lead to NaN, but a certain default value.

Upvotes: 0

Views: 321

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243579

From a comment of the OP:

Ok, that means my only option is using <xsl:choose>..., correct?

While the way you attempt it produces unpredictable results due to reasons explained both by @Michael Kay and by me in my comments, there are still ways to do what you want (produce either the value of the attrib attribute or a default value (0):

concat(@attrib,
       substring(0, 2 -not(@attrib))
       )

This produces the value of the attrib attribute (if this attribute is present) or (if not present) the default value 0.

Complete XSLT solution:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="x">
  <xsl:value-of select=
   "concat(@attrib,
           substring('0', 2 -not(@attrib))
           )"/>

==========
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the following XML document:

<t>
 <x attrib="abc"/>
 <x/>
</t>

the wanted, correct result is produced:

 abc

==========

 0

==========

Upvotes: 1

Michael Kay
Michael Kay

Reputation: 163595

This version of exsl:node-set() presumably creates a node that is in a different tree from from the node @attrib. When two nodes are in different trees, it is implementation-dependent which of them comes first in document order. The construct (X|Y)[position()=1] (or equivalently (X|Y)[1]) selects whichever of X and Y comes first in document order. Therefore it's essentially unpredictable whether it selects X or Y.

Upvotes: 1

Related Questions