Thank you for the reference.
In fact, for I'm satisfied with Michael Kay's response, as I'm using
Saxon.
On the other hand I've implemented a natural-sort function in xslt 2
(quoted in original post with a small bug)
--
Vladimir Nesterovsky
http://www.nesterovsky-bros.com/
-------- Original Message --------
From: "Hermann Stamm-Wilbrandt" <STAMMW(_at_)de(_dot_)ibm(_dot_)com>
Sent: Tuesday, March 01, 2011 3:15 PM
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: Re: [xsl] Natural sort of strings
Vladimir,
as Michael said you can go with saxon-specific alphanumeric collation.
In old post "sorting on decimal" there was an (XSLT 1.0) alternative to
using collations (restricted):
http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200905
/msg00208.html
It depends on your number ranges whether that may be helpful.
Mit besten Gruessen / Best wishes,
Hermann Stamm-Wilbrandt
Developer, XML Compiler, L3
Fixpack team lead
WebSphere DataPower SOA Appliances
https://www.ibm.com/developerworks/mydeveloperworks/blogs/HermannSW/
----------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschaeftsfuehrung: Dirk Wittkopp
Sitz der Gesellschaft: Boeblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
From: "Vladimir Nesterovsky" <vladimir(_at_)nesterovsky-bros(_dot_)com>
To: <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
Date: 02/24/2011 11:57 AM
Subject: [xsl] Natural sort of strings
Hello!
I needed to sort strings in "natural" order. That means that I needed
output like this:
"item1/1"
"item2/1"
"item2/2"
"item2/12"
"item3"
"item4"
"item5"
"item6"
"item7"
"item8"
"item9"
"item10/1"
"item11"
"item12"
"item13"
"item14"
"item15"
"item16"
"item17"
"item18"
"item19"
"item20"
The task looks simple but my implementation is surprisingly untrivial.
Is there simple one?
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:t="http://www.nesterovsky-bros.com/xslt/public"
exclude-result-prefixes="t xs">
<xsl:template match="/" name="main">
<xsl:variable name="items" as="xs:string*">
<xsl:for-each select="1 to 20">
<xsl:sequence select="concat('item', .)"/>
</xsl:for-each>
<xsl:sequence select="'item1/1'"/>
<xsl:sequence select="'item10/1'"/>
<xsl:sequence select="'item2/1'"/>
<xsl:sequence select="'item2/2'"/>
<xsl:sequence select="'item2/12'"/>
</xsl:variable>
<xsl:variable name="regular-sort" as="xs:string*">
<xsl:perform-sort select="$items">
<xsl:sort select="." order="ascending"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:variable name="natural-sort" as="xs:string*"
select="t:natural-sort($regular-sort, true())"/>
<xsl:message>
<xsl:text>Regular sort:
</xsl:text>
<xsl:for-each select="$regular-sort">
<xsl:value-of select="."/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>
Natural sort:
</xsl:text>
<xsl:for-each select="$natural-sort">
<xsl:value-of select="."/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:message>
</xsl:template>
<!--
Sorts strings in "natural" order.
$values - values to sort.
$ascending - true for ascending, and false for descending order.
Returns an ordered sequence of values.
-->
<xsl:function name="t:natural-sort" as="xs:string*">
<xsl:param name="values" as="xs:string*"/>
<xsl:param name="ascending" as="xs:boolean"/>
<xsl:variable name="indices" as="xs:integer*"
select="t:natural-sort-indices($values, $ascending, false())"/>
<xsl:sequence select="
for $i in $indices return
$values[$i]"/>
</xsl:function>
<!--
Natural sort implementation.
$values - values to sort.
$ascending - true for ascending, and false for descending order.
$number - true for a number, and false for a non number start
prefix.
Returns an ordered sequence of value indices.
-->
<xsl:function name="t:natural-sort-indices" as="xs:integer*">
<xsl:param name="values" as="xs:string*"/>
<xsl:param name="ascending" as="xs:boolean"/>
<xsl:param name="number" as="xs:boolean"/>
<xsl:for-each-group select="1 to count($values)"
group-by="
for
$i in .,
$value in $values[$i]
return
(
if ($number) then
t:number-prefix($value)
else
t:non-number-prefix($value)
)">
<xsl:sort
select="
if ($number) then
xs:integer(current-grouping-key())
else
current-grouping-key()"
order="{
if ($ascending) then
'ascending'
else
'descending'
}"/>
<xsl:variable name="start" as="xs:integer"
select="string-length(current-grouping-key()) + 1"/>
<xsl:variable name="group" as="xs:integer+"
select="current-group()"/>
<xsl:choose>
<xsl:when test="count($group) = 1">
<xsl:sequence select="$group"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="next" as="xs:integer+" select="
t:natural-sort-indices
(
(
for $i in $group return
substring($values[$i], $start)
),
$ascending,
not($number)
)"/>
<xsl:sequence select="
for $i in $next return
$group[$i]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<!--
Gets a number prefix for a value.
$value - a value to get
prefix for.
Returns a value prefix.
-->
<xsl:function name="t:number-prefix" as="xs:string?">
<xsl:param name="value" as="xs:string"/>
<xsl:variable name="parts" as="xs:string*">
<xsl:analyze-string select="$value" regex="^[0-9]+">
<xsl:matching-substring>
<xsl:sequence select="."/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:variable>
<xsl:sequence select="$parts[1]"/>
</xsl:function>
<!--
Gets a non number prefix for a value.
$value - a value to
get prefix for.
Returns a value prefix.
-->
<xsl:function name="t:non-number-prefix" as="xs:string?">
<xsl:param name="value" as="xs:string"/>
<xsl:variable name="parts" as="xs:string*">
<xsl:analyze-string select="$value" regex="^[^0-9]+">
<xsl:matching-substring>
<xsl:sequence select="."/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:variable>
<xsl:sequence select="$parts[1]"/>
</xsl:function>
</xsl:stylesheet>
Thanks
--
Vladimir Nesterovsky
http://www.nesterovsky-bros.com/
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--