views:

793

answers:

1
+5  A: 

Splitting the label text into text and number part using substring-before and substring-after will do in your example (however, this is not a general approach, but you get the idea):

<xsl:template match="/">
    <xsl:apply-templates select="colors/item">
      <xsl:sort select="substring-before(label, ' ')" data-type="text" order="ascending"/>
      <!--1st sort-->
      <xsl:sort select="substring-after(label, ' ')" data-type="number" order="ascending"/>
      <!--2nd sort-->
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="item">
    <xsl:value-of select="label"/>
    <xsl:if test="position() != last()">, </xsl:if>
  </xsl:template>

This gives the following output:

Blue 12, Blue 117, Orange 3, Orange 26, Yellow 10, Yellow 100


Update

A more generic way to solve your sorting problem would be to have the select attribute of the xls:sort element contain a string which is sortable according to the sort rules that you expect. E.g. in this string all numbers could be padded with leading 0's so that lexicgraphically sorting them as data-type="text" will result in the correct alphanumeric order.

If you are using the XSLT engine of .NET you could use a simple extension function in C# to pad numbers with leading 0's:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:myExt="urn:myExtension"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                exclude-result-prefixes="msxsl myExt">
  <xsl:output method="xml" indent="yes" />

  <msxsl:script language="C#" implements-prefix="myExt">

    <![CDATA[
        private static string PadMatch(Match match)
        {
            // pad numbers with zeros to a maximum length of the largest int value 
            int maxLength = int.MaxValue.ToString().Length;
            return match.Value.PadLeft(maxLength, '0');
        }

        public string padNumbers(string text)
        {
            return System.Text.RegularExpressions.Regex.Replace(text, "[0-9]+", new System.Text.RegularExpressions.MatchEvaluator(PadMatch));
        }
    ]]>

  </msxsl:script>
  <xsl:template match="/">
    <sorted>
      <xsl:apply-templates select="colors/item">
        <xsl:sort select="myExt:padNumbers(label)" data-type="text" order="ascending"/>
      </xsl:apply-templates>
    </sorted>
  </xsl:template>

  <xsl:template match="item">
    <xsl:value-of select="label"/>
    <xsl:if test="position() != last()">, </xsl:if>
  </xsl:template>

</xsl:stylesheet>
0xA3
thanks divo... yeah I guess my sample data is a bit too generic ;-) In reality there may not be any delimiter and/or the position of the digits could be anywhere.
scunliffe