Reputation: 63
I want to compare two software versions using xsl, for example 1.13 and 1.4 and I want 1.13 to be larger than 1.4.
However, the following xslt condition will fail.
<xsl:if test="1.13 >= 1.4">
Instead I opted for an approacah where I remove the integer part using substring-after() so that only the remainder is used in the comparison (assuming that the integer part is the same for now).
<xsl:if test="substring-after(1.13, ".") >= substring-after(1.4, ".")">
(actually I had to write it like this)
<xsl:if test="substring-after(1.13, ".") >= substring-after(1.4, ".")">
That works for the values 1.13 and 1.4. However, when I compared the values 1.10 and 1.4, the comparison fails.
Is there a better way of doing this comparison?
Upvotes: 3
Views: 1306
Reputation: 163635
It depends on what XSLT processor and version you are using. With Saxon, you can do
<xsl:template match="/" name="main">
<out>
<xsl:value-of select="compare('1.13', '1.4', 'http://saxon.sf.net/collation?alphanumeric=yes')"/>
</out>
</xsl:template>
which returns 1 indicating that the first argument is considered greater than the second. You could also write
<xsl:if test="'1.13' < '1.4'"
default-collation="http://saxon.sf.net/collation?alphanumeric=yes"/>
If you don't want to be dependent on processor-dependent collation URIs, then in XSLT 3.0 you could use the fn:sort() function which allows you to provide a function to compute your own sort key, which in this case might be tokenize($x, '\.')!xs:integer(.)
.
With earlier XSLT releases and no processor-dependent features, use xsl:sort with multiple sort keys computed using substring-before and substring-after.
Upvotes: 2
Reputation: 3247
You can try converting the versions to strings or integers and then perform a comparison. E.g. version 1.13
will be converted to 0113
and version 1.4
will be converted to 0104
and then 0113
will be compared with 0104
.
Below XSLT uses XSLT 1.0 to perform the comparison for single .
separator.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="Versions">
<xsl:variable name="oldVersion">
<xsl:call-template name="convert-ver-to-string">
<xsl:with-param name="ver" select="OldVersion"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="newVersion">
<xsl:call-template name="convert-ver-to-string">
<xsl:with-param name="ver" select="NewVersion"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$newVersion > $oldVersion">
<Out>New greater than Old</Out>
</xsl:when>
<xsl:otherwise>
<Out>Old greater than New</Out>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="convert-ver-to-string">
<xsl:param name="ver" />
<xsl:variable name="updVer">
<xsl:choose>
<xsl:when test="contains($ver, '.')">
<xsl:value-of select="$ver" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($ver, '.0')" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="format-number(substring-before($updVer, '.'), '00')" />
<xsl:value-of select="format-number(substring-after($updVer, '.'), '00')" />
</xsl:template>
</xsl:stylesheet>
Sample Input XML
<Versions>
<OldVersion>1.3</OldVersion>
<NewVersion>1.12</NewVersion>
</Versions>
Output
<Out>New greater than Old</Out>
Upvotes: 2