What is the difference between < and lt when comparing values in XSLT?

Viewed 179

I am trying to figure out what is the difference between < and lt when comparing two values in XSLT.

Assuming the XML looks like below:

<root>
    <field time="PT22M00.000S" value="red" number="22"/>
    <field2 time="PT23M00.000S" value="blue" number="23"/>
</root>

I will get the following results for each expression:

  • Comparing dates: if (xs:dayTimeDuration(/root/field/@time) lt xs:dayTimeDuration(/root/field2/@time)) then (/root/field/@value) else (/root/field2/@value)

The result is "red"

  • Comparing numbers: if (/root/field/@number &lt; /root/field2/@number) then (/root/field/@value) else (/root/field2/@value)

The result is "red"

  • Comparing dates using < : if (xs:dayTimeDuration(/root/field/@time) &lt; 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!

1 Answers
  • Comparing dates using < : if (xs:dayTimeDuration(/root/field/@time) &lt; 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:

  1. 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.

  2. Atomization is applied to each operand. After atomization, each operand is a sequence of atomic values.

  3. 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 &lt; /root/field2/@number)
        then string(/root/field/@value)
        else string(/root/field2/@value)"/>
    <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="xs:dayTimeDuration(/root/field/@time) 
                     &lt; 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 &lt; $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!

Related