Link to home
Start Free TrialLog in
Avatar of hc0904pcd
hc0904pcdFlag for Australia

asked on

Write a variable number of sort selects?

Trying to sort a list with a custom character-by-character sort.

Sample input:
<items>
  <item>abc</item>
  <item>a!c</item>
  <item>a2c</item>
</items>

Desired output is sorted by letter, then number, then non-alphanumeric (exclamation mark, spaces etc). For each character.

The xsl below, with 3 sort selects per character, works. But it's ugly code, and to process sorting of unknown input I'd need to anticipate potential string-length of up to at least 50 characters....

I was hoping there'd be a way to iterate from $iterator to $length_second_longest_string, writing 3 sort selects for each character.
But I can't see how...


<xsl:variable name="alphabet" select="'abcdefghijklmnipqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:variable name="numberic" select="'012345679'" />
<xsl:variable name="alphanumeric" select="concat($alphabet, $numberic)" />
<xsl:variable name="iterator" select="1" />
<xsl:variable name="length_second_longest_string">
      <xsl:for-each select="//item">
            <xsl:sort select="string-length(.)" order="descending" data-type="number" />
            <xsl:if test="position() = 2">
                  <xsl:value-of select="string-length(.)"/>
            </xsl:if>      
      </xsl:for-each>
</xsl:variable>

<xsl:template match="/">                              
      <xsl:for-each select="//item">
            <xsl:sort select="number(contains($alphanumeric, substring(.,1,1)))" order="descending" data-type="number" />
            <xsl:sort select="substring(.,1,1)" data-type="number" order="ascending" />
            <xsl:sort select="substring(.,1,1)" data-type="text" order="ascending" />
            
            <xsl:sort select="number(contains($alphanumeric, substring(.,2,1)))" order="descending" data-type="number" />
            <xsl:sort select="substring(.,2,1)" data-type="number" order="ascending" />
            <xsl:sort select="substring(.,2,1)" data-type="text" order="ascending" />
            
            <xsl:sort select="number(contains($alphanumeric, substring(.,3,1)))" order="descending" data-type="number" />
            <xsl:sort select="substring(.,3,1)" data-type="number" order="ascending" />
            <xsl:sort select="substring(.,3,1)" data-type="text" order="ascending" />
                        
            <xsl:copy-of select="."/>
      </xsl:for-each>            
</xsl:template>


All suggestions appreciated.
ASKER CERTIFIED SOLUTION
Avatar of Gertone (Geert Bormans)
Gertone (Geert Bormans)
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of hc0904pcd

ASKER

thank you :)
That was exactly the help I needed!


<xsl:variable name="sort_input"  select="'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ012345679 ?!*'" />
<xsl:variable name="sort_output" select="' !*?012345679aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ'" />      
<xsl:template match="/">
      <items>
            <standard_sort>
                  <xsl:for-each select="//item">
                        <xsl:sort select="." />
                        <xsl:copy-of select="."/>
                  </xsl:for-each>
            </standard_sort>      
            <custom_sort>                  
                  <xsl:for-each select="//item">                  
                        <xsl:sort select="translate(., $sort_input, $sort_output)" data-type="text" order="ascending" />                                          
                        <xsl:copy-of select="." />
                  </xsl:for-each>            
            </custom_sort>      
      </items>      
</xsl:template>

input:
<items>
      <item>abc</item>
      <item>a!c</item>
      <item>a2c</item>
</items>

output:
<items>
      <standard_sort>
            <item>a!c</item>
            <item>a2c</item>
            <item>abc</item>
      </standard_sort>
      <custom_sort>
            <item>abc</item>
            <item>a2c</item>
            <item>a!c</item>
      </custom_sort>
</items>