XSLT Sort Alphabetically & Numerically Problem

Bryan picture Bryan · Apr 19, 2010 · Viewed 8.1k times · Source

I have a group of strings ie g:lines = '9,1,306,LUCY,G,38,12'

I need the output to be in XSLT 1.0:

1,9,12,38,306,G,LUCY

This is my current code:

<xsl:for-each select="$all_alerts[g:problem!='normal_service'][g:service='bus']">
  <xsl:sort select="g:line"/>
  <xsl:sort select="number(g:line)" data-type="number"/>
  <xsl:value-of select="normalize-space(g:line)" /><xsl:text/>
  <xsl:if test="position()!=last()"><xsl:text>,&#160;</xsl:text></xsl:if>
</xsl:for-each>

I can get it to only display '1, 12, 306, 38, 9, G, LUCY' because the 2nd sort isn't being picked up.

Anyone able help me out?

Answer

Tim C picture Tim C · Apr 20, 2010

To achieve this using just one xsl:foreach statement, try the following:

<xsl:for-each select="$all_alerts[g:problem!='normal_service'][g:service='bus']"> 
  <xsl:sort select="not(number(g:line))"/> 
  <xsl:sort select="number(g:line)" data-type="number"/> 
  <xsl:sort select="g:line"/> 
  <xsl:value-of select="normalize-space(g:line)" /><xsl:text/> 
  <xsl:if test="position()!=last()"><xsl:text>,&#160;</xsl:text></xsl:if> 
</xsl:for-each> 

The first xsl:sort sorts on whether the line is a number or not. The not() returns false if the line is a number, and true if it isn't. false is sorted before true, and so the numbers come out first. If you omit this sort, the letters will appear first.

The next xsl:sort sorts numerically, and so will sort the numbers correctly, but not affect the letters (which all return NaN when number() is applied).

The final xsl:sort will sort the letters alphabetically.