7

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?

2
  • You have non numeric items in your list, how are they supposed to be numerically sorted? Commented Apr 19, 2010 at 19:39
  • I know that the items are both numbers and letters, I just need numbers numerically sorted followed by the letters alphabetically sorted. What do i need to do to make that happen Commented Apr 19, 2010 at 19:50

4 Answers 4

14

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.

Sign up to request clarification or add additional context in comments.

Comments

0
<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?

3 Comments

I received an error, probably because that code is for 2.0 and im using 1.0 javax.xml.transform.TransformerConfigurationException: javax.xml.transform.TransformerException: javax.xml.transform.TransformerException: Could not find function: if
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.
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.
0

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.

1 Comment

The code above gave me this output: 1, 12, 306, 38, 9, G, LUCY
0

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.