Recipe 1.9. Coping with XPath 2.0's Extended Type System
Problem
XPath 2.0's stricter type rules
have you cursing the W3C and longing for Perl.
Solution
Most incompatibilities between XPath/XSLT 1.0 and 2.0 come from type
errors. This is true regardless of whether a schema is present or
not. You can eliminate many problems encountered in porting legacy
XSLT 1.0 to XSLT 2.0 with respect to XPath differences by running in
1.0 compatibility mode.
<xsl:stylesheet version="1.0">
<!-- ... -->
</xsl:stylesheet>
In my opinion, eventually you will want to stop using compatibility
mode. XPath 2.0 provides several facilities for dealing with type
conversions. First, you can use conversion functions explicitly.
(: Convert the first X child of the context to a number. :)
number(X[1]) + 17
(: Convert a number in $n to a string. :)
concat("id-", string($n))
XPath 2.0 also provides type constructors so you can explicitly
control the interpretation of a string.
(: Construct a date from a string. :)
xs:date("2005-06-01")
(: Construct doubles from strings. :)
xs:double("1.1e8") + xs:double("23000")
Finally, XPath has the operators castable as,
cast as, and TReat
as. Most of the time, you want to use the first
two.
if ($x castable as xs:date) then $x cast as xs:date else xs:date("1970-01-01")
The operator, treat as, is not
a conversion per se but rather an assertion that tells the XPath
processor that you promise at runtime a value will conform to a
specified type. If this turns out not to be the case, then a type
error will occur. XPath 2.0 added treat
as so XPath implementers could perform static
(compile time) type checking in addition to dynamic type checking
while allowing programmers to selectively disable static type checks.
Static type checking XSLT 2.0 implementations will likely be rare so
you can ignore TReat as for the
time being. It is far more likely to arise in higher-end XQuery
processors that do static type checking to facilitate various
optimizations.
Discussion
Running in 1.0 compatibility mode with an XSLT 2.0 processor does not
mean you cannot use any of the new 2.0 features. It simply enables
certain XPath 1.0 conversion rules.
(: In compatability mode, the following evaluates to 18.1 but is a type error in 2.0. :)
"1.1" + "17"
(: In compatability mode, the following evaluates to 2 but is a type error in 2.0. :)
string-length(1 + 2 + 3 + 4 + 5)
<poem>
<line>There once was a programmer from Nantucket.</line>
<line>Who liked his bits in a bucket.</line>
<line>He said with a grin</line>
<line>and drops of coffee on his chin,</line>
<line>"If XSLT had a left-shift, I would love it!"</line>
<poem>
(: In compatability mode, both
expressions evaluate to 43 but the first is a type error in 2.0. :)
string-length(/poem/line)
string-length(/poem/line[1])
|