- Comparing dates using < :
if (xs:dayTimeDuration(/root/field/@time) < xs:dayTimeDuration(/root/field2/@time)) then (/root/field/@value) else (/root/field2/@value)
The result is "blue"
Are there any explanations between the differences between these two?
Thanks!
Short answer:
The above result is produced when an XSLT 1.0 (<xsl:stylesheet version="1.0" ...>) transformation is applied. Replace the value of the version attribute with "2.0" or greater and then all results will be "red" as expected.
Long answer:
When an XSLT 2.0 processor is executing an XSLT 1.0 transformation, this is done in XPath 1.0 compatibility mode .
In particular, here is the definition of the semantics of a general comparison (including <) in XPath 1.0 compatibility mode:
If XPath 1.0 compatibility mode is true, a general comparison is
evaluated by applying the following rules, in order:
If either operand is a single atomic value that is an instance of
xs:boolean, then the other operand is converted to xs:boolean by
taking its effective boolean value.
Atomization is applied to each operand. After atomization, each
operand is a sequence of atomic values.
If the comparison operator is <, <=, >, or >=, then each item in both
of the operand sequences is converted to the type xs:double by
applying the fn:number function. (Note that fn:number returns the
value NaN if its operand cannot be converted to a number.)
This is exactly what happens.
The two dates are converted to numbers and this results in NaN in both cases.
And by definition, NaN < NaN is false()
To prove this, run the following XSLT transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:sequence select=
"if (xs:dayTimeDuration(/root/field/@time)
lt xs:dayTimeDuration(/root/field2/@time))
then string(/root/field/@value)
else string(/root/field2/@value)"/>
<xsl:sequence select=
"if (/root/field/@number < /root/field2/@number)
then string(/root/field/@value)
else string(/root/field2/@value)"/>
<xsl:sequence select=
"if (xs:dayTimeDuration(/root/field/@time)
< xs:dayTimeDuration(/root/field2/@time))
then string(/root/field/@value)
else string(/root/field2/@value)"/>
===============================================
<xsl:sequence select="xs:dayTimeDuration(/root/field/@time)
< xs:dayTimeDuration(/root/field2/@time)"/>
<xsl:variable name="v1" select="data(xs:dayTimeDuration(/root/field/@time))"/>
<xsl:sequence select="$v1"/>
<xsl:variable name="v2" select="data(xs:dayTimeDuration(/root/field2/@time))"/>
<xsl:sequence select="$v2"/>
<xsl:sequence select="$v1 < $v2"/>
================================================
<xsl:sequence select="number($v1)"/>
<xsl:sequence select="number($v2)"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<root>
<field time="PT22M00.000S" value="red" number="22"/>
<field2 time="PT23M00.000S" value="blue" number="23"/>
</root>
the result is:
red red blue
===============================================
false PT22M PT23M false
================================================
NaN NaN
exactly as it should be, as per the explanation above.
We also get this from Saxon, essentially telling us that XPath 1.0 compatibility mode was indeed used:
Saxon 9.1.0.1J from Saxonica
Java version 1.8.0_191
Warning: at xsl:stylesheet on line 2 column 46 of xxxx.xsl:
Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor
Now, in the same transformation replace the version="1.0" attribute with "version="2.0" and run the transformation.
The result now is:
red red red
===============================================
true PT22M PT23M true
================================================
NaN NaN
Just because the XSLT processor executed the transformation as a true XSLT 2.0 one!