Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xpath 1 and xpath 2 return different results when determining min and max value

I have following question relating to XPATH1 and XPATH2:

<document>
    <val>3</val>
    <val>11</val>
    <val>3</val>
    <val>2</val>
    <val>12</val>
    <val>5</val>
    <val>0</val>
    <val>7</val>
</document>

xpath1: max

//val[not(. < //val)]

min:

//val[not(. > //val)]

xpath2:

document/val[. = max(//val)]

document/val[. = min(//val)]

Why don't I get the same result in XPATH2 processing with the xpath1-max query:

//val[not(. < //val)]

It seems that I get the LAST node (with val 7), but not the highest value ... the other way around for MIN value works fine with XPATH2 processing:

//val[not(. > //val)]

Can someone help me out there ?

like image 785
Fl0R1D3R Avatar asked Nov 02 '12 11:11

Fl0R1D3R


1 Answers

Very good point.

In xpath 1 (and xslt 1.0), //val[not(. < //val)] is inherently casting the text values to numbers, and doing the comparison on numbers.

Hence, you get the correct min and max values.

However, in xpath 2 (and xslt 2.0), the text isn't cast to numeric, and instead, a string comparison is done. So using string comparison, '7' is > '12' and hence 7 will still be the highest value (it isn't returning just the last value in the list - try swapping the order of values around)

So what you should do to be safe in both xslt 1 and 2 is to use the number() function to do the cast on the text, to ensure that a numeric comparison is done.

Max:

//val[not(number(.) &lt; //val)]

Min:

//val[not(number(.) &gt; //val)]

Using Saxon with the stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <x>
            <Max1>
                <xsl:value-of select="//val[not(number(.) &lt; //val)]" />
            </Max1>
            <Min1>
                <xsl:value-of select="//val[not(number(.) &gt; //val)]" />
            </Min1>
            <Max2>
                <xsl:value-of select="/document/val[. = max(//val/text())]" />
            </Max2>
            <Min2>
                <xsl:value-of select="/document/val[. = min(//val/text())]" />
            </Min2>
        </x>
    </xsl:template>
</xsl:stylesheet>

Returns

<x>
   <Max1>12</Max1>
   <Min1>0</Min1>
   <Max2>12</Max2>
   <Min2>0</Min2>
</x>

as expected.

like image 195
StuartLC Avatar answered Oct 13 '22 06:10

StuartLC