Home > Software engineering >  XSLT Custom Sort with Symbols, Letters, and Numbers (O counts as a zero)
XSLT Custom Sort with Symbols, Letters, and Numbers (O counts as a zero)

Time:03-25

I have a table with a series of rows of part numbers. I need to sort the output by a series of very specific sequence and can't figure out how to do the

<xsl:apply-templates select="row">
    <xsl:sort select="row/partNumber"/>
</xsl:apply-templates>

properly. I need them to be sort by:

  1. Symbols (specifically a slash, then a period, then a dash)
  2. Letters (except for the letter O)
  3. Numbers (with the letter O counting as a 0)

Does anybody have any ideas?

edited to add: I'm using XSLT 2.0 and saxon. And some of the sample data is

<row>
    <partNumber>AN931-4-13</partNumber>
</row>
<row>
    <partNumber>AN931.2</partNumber>
</row>
<row>
    <partNumber>AO931</partNumber>
</row>
<row>
    <partNumber>AP417-3</partNumber>
</row>
<row>
    <partNumber>AP417/3</partNumber>
</row>

It should output as:

AN931.2
AN931-4-13
AP417/3
AP417-3
AO931

CodePudding user response:

I tried to construct some collation rules for your syntax and feed it to the Saxon configuration, in the following sample done with XQuery 3.1 and the transform function and all configuration data inline:

transform(map {
  'source-node' : .,
  'stylesheet-node' : <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="3.0"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                exclude-result-prefixes="#all"
                expand-text="yes">

    <xsl:output method="html" indent="yes" html-version="5"/>

    <xsl:mode on-no-match="shallow-copy"/>
    
    <xsl:template match="rows">
      <xsl:copy>
        <xsl:apply-templates select="row">
          <xsl:sort select="partNumber" collation="http://example.com/mc1"/>
        </xsl:apply-templates>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="/" name="xsl:initial-template">
        <xsl:next-match/>
    </xsl:template>

</xsl:stylesheet>,
  'vendor-options' : map {
     QName('http://saxon.sf.net/', 'configuration'): 
       <configuration xmlns="http://saxon.sf.net/ns/configuration">
         <collations>
           <collation uri="http://example.com/mc1"
             alphanumeric="yes"
             rules="&lt; a,A &lt; b,B &lt; c,C &lt; d,D &lt; e,E &lt; f,F &lt; g,G &lt; h,H &lt; i,I &lt; j,J &lt; k,K &lt; l,L &lt; m,M &lt; n,N  &lt; p,P &lt; q,Q &lt; r,R &lt; s,S &lt; t,T &lt; u,U &lt; v,V &lt; w,W &lt; x,X &lt; y,Y &lt; z,Z &lt; 0 = o = O &lt; 1 &lt; 2 &lt; 3 &lt; 4 &lt; 5 &lt; 6 &lt; 7 &lt; 8 &lt; 9 &lt; '/' &lt; '.' &lt; '-'"/>           
         </collations>
       </configuration>
  }
}
)?output

For the input

<rows>
<row>
    <partNumber>AN931-4-13</partNumber>
</row>
<row>
    <partNumber>AN931.2</partNumber>
</row>
<row>
    <partNumber>AO931</partNumber>
</row>
<row>
    <partNumber>AP417-3</partNumber>
</row>
<row>
    <partNumber>AP417/3</partNumber>
</row>
</rows>

I get the output

<rows>
   <row>
      <partNumber>AN931.2</partNumber>
   </row>
   <row>
      <partNumber>AN931-4-13</partNumber>
   </row>
   <row>
      <partNumber>AP417/3</partNumber>
   </row>
   <row>
      <partNumber>AP417-3</partNumber>
   </row>
   <row>
      <partNumber>AO931</partNumber>
   </row>
</rows>

using Saxon 11.2 HE, now also tested online with 10.6 HE at https://xqueryfiddle.liberty-development.net/94hwpia.

I hope, whatever Saxon 9 version you use, that you can just feed it an appropriate configuration file with an appropriate collation similar to or based on the one in the above sample.

  • Related