views:

138

answers:

1

Given

<xsl:variable name="datePrecision" as="element()*">
  <p>Year</p>
  <p>Month</p>
  <p>Day</p>
  <p>Time</p>
  <p>Timestamp</p>
</xsl:variable>

The expression

$datePrecision[5] 

returns a nodeSet containing one text node with value "Timestamp", as expected.

Later in a template, with a context element having an attribute

@precision="5"

I try the following expressions but all return an empty string:

$datePrecision[@precision]
$datePrecision[number(@precision)]
$datePrecision[xs:decimal(@precision)]

However, the following sequence does what I want

<xsl:variable name="prec" select="number(@precision)"/>
... $datePrecision[$prec] ...

Using Oxygen/XML's debugger I've stepped to the point where the expression is about to be evaluated and display the following in the watch window:

Expression                          Value            Nodes/Values Set
--------------------------          ---------------  -----------------------
$datePrecision[5]                   Node Set(1)      #text Timestamp
@precision                          Node Set(1)      precision 5
$datePrecision[@precision]  
number(@precision)                  5
$datePrecision[number(@precision)]  
$prec                               5
$datePrecision[$prec]               Node Set(1)      #text Timestamp

Obviously I've missed something fundamental about how attribute nodes are atomized for use in a predicate, but can't find anything in the docs (Michael Kay's XSLT/XPATH 2.0, 4th ed) that would explain this difference.

Can someone explain why this is occurring, and point me to where, in either the XSLT 2.0 spec or Michael Kay's book, where this is described?

(the XSLT processor is Saxon-PE 9.2.0.3)

+1  A: 

Obviously I've missed something fundamental

Yes. The XPath expression:

$datePrecision[@precision]

means: all elements in $datePrecision that have an attribute named precision.

But you want @precision to mean the attribute named precision of the currnet node that is matched by the template.

XSLT provides the current() function exactly for this purpose. Use:

 $datePrecision[current()/@precision]

UPDATE: As Martin Honnen hinted, the OP probably wants to get the 5th element out of $datePrecision -- something not immediately visible from the description of the problem. In this case, it may be necessary to use:

 $datePrecision[position() = current()/@precision]
Dimitre Novatchev
Ah yes, I see... I've just gotten back into XSLT after an 18-month break, and obviously have been away from it far too long :-) Thanks for the quick response.
Jim Garrison
That still leaves one question. What is the meaning of the predicate in `$datePrecision[number(@precision)]`?
Jim Garrison
@Jim-Garrison As I explained in my answer, if any of the elements contained in the node-set `$datePrecision` has an attribute named `precision` and its value happens to be numeric and it is not 0, then this (and all such) element(s) will be selected. To verify this, make some of the elements in `$datePrecision` have a `precision` attribute with different numeric and non-numeric values and see what the expression selects.
Dimitre Novatchev
Dimitre, if Jim wants to select the fifth item in the $datePrecision sequence if the attribute value is "5" then I think you need `$datePrecision[position() = current()/@precision]` or `$datePrecision[xsd:integer(current()/@precision)]`. Simply putting current()/@precision into the predicate does not make it a positional predicate, unless we had a schema giving that attribute a numeric type.
Martin Honnen
@Martin-Honnen: Thank you, this was not immediately visible from the description of the problem. I added it as an update and acknowledged your contribution.
Dimitre Novatchev