views:

282

answers:

4

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?

A: 
<xsl:template match="/">
  <xsl:for-each select="(9,1,306,'LUCY','G',89)" >
    <xsl:sort select="if (number()) then () else ."/>
    <xsl:sort select="number(.)" data-type="number" />
    <xsl:value-of select="."/>
    <xsl:value-of select="', '" />
  </xsl:for-each>
</xsl:template>

gives me

1, 9, 89, 306, G, LUCY,

I guess that is what you need, right?

Patrick
I received an error, probably because that code is for 2.0 and im using 1.0javax.xml.transform.TransformerConfigurationException: javax.xml.transform.TransformerException: javax.xml.transform.TransformerException: Could not find function: if
Bryan
I'd dare to say that you should never ever get used to XSLT 1.0. It is so far behind 2.0. Sorry that I can't help you there, but you have a rather advanced wish and if you want to stick to XSLT 1.0, you might be out of luck.You have seen the trick in the answer: only use the text value if the item is not a number. If it is, return "nothing". So if you (or someone else) can map this to XSLT 1.0 you should be done.I will give up on this question since I don't ever want to get into XSLT 1.0 mode again. Sorry again.
Patrick
No i understand, my company is using an open source CMS called Alfresco and it won't allow me to use XSLT 2.0. Thank you for your help.
Bryan
A: 

In XSLT 1.0 I think you need something like this:

<xsl:for-each select="$all_alerts[g:problem!='normal_service'][g:service='bus']">  
    <xsl:sort select="g:line[number(g:line) != number(g:line)]"/>  
    <xsl:sort select="g:line[number(g:line) = 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>

number($foo) != number($foo) is XSLT 1.0 idiom for testing if a value is not a number.

Another (more clean I guess) solution would be to select/sort first numbers, then others.

Oleg Tkachenko
The code above gave me this output:1, 12, 306, 38, 9, G, LUCY
Bryan
A: 

I believe this accomplishes what you want.

I split out the evaluation/sort of numbers first and then text node values.

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

    <xsl:for-each select="$all_alerts[g:problem!='normal_service'][g:service='bus'][number(g:line)!=number(g:line)]">
        <xsl:sort select="g:line[number(g:line) != number(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>
Mads Hansen
+3  A: 

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.

Tim C
Thank you so much, life saver!
Bryan