2009-04-22 10 views
2

Selon le code XML suivant, quel est le meilleur moyen d'obtenir un tri alphanumérique dans XSL?Comment appliquer un tri alphanumérique dans XSLT

Modifier: pour clarifier, le XML ci-dessous est juste un échantillon simple le vrai XML contiendrait beaucoup plus de valeurs variantes.

<colors> 
    <item> 
    <label>Yellow 100</label> 
    </item> 
    <item> 
    <label>Blue 12</label> 
    </item> 
    <item> 
    <label>Orange 3</label> 
    </item> 
    <item> 
    <label>Yellow 10</label> 
    </item> 
    <item> 
    <label>Orange 26</label> 
    </item> 
    <item> 
    <label>Blue 117</label> 
    </item> 
</colors> 

E.g. Je veux un résultat final dans cet ordre:

Blue 12, Blue 117, Orange 3, Orange 26, Yellow 10, Yellow 100 

Ceci est « efficacement » ce que je veux.

<xsl:apply-templates select="colors/item"> 
    <xsl:sort select="label" data-type="text" order="ascending"/><!--1st sort--> 
    <xsl:sort select="label" data-type="number" order="ascending"/><!--2nd sort--> 
</xsl:apply-templates> 

<xsl:template match="item"> 
    <xsl:value-of select="label"/> 
    <xsl:if test="position() != last()">,</xsl:if> 
</xsl:template> 
+0

Je mis à jour ma réponse avec une approche plus générique au problème. –

Répondre

6

Fractionnement le texte de l'étiquette dans la partie texte et numéro à l'aide substring-before et substring-after fera dans votre exemple (cependant, ce n'est pas une approche générale, mais vous voyez l'idée):

<xsl:template match="/"> 
    <xsl:apply-templates select="colors/item"> 
     <xsl:sort select="substring-before(label, ' ')" data-type="text" order="ascending"/> 
     <!--1st sort--> 
     <xsl:sort select="substring-after(label, ' ')" data-type="number" order="ascending"/> 
     <!--2nd sort--> 
    </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="item"> 
    <xsl:value-of select="label"/> 
    <xsl:if test="position() != last()">, </xsl:if> 
    </xsl:template> 

Cette donne le résultat suivant:

Blue 12, Blue 117, Orange 3, Orange 26, Yellow 10, Yellow 100 

Mise à jour

Une façon plus générique pour résoudre votre problème de tri serait d'avoir l'attribut select de l'élément xls:sort contient une chaîne qui est classable selon les règles de tri que vous attendez. Par exemple. Dans cette chaîne, tous les nombres peuvent être complétés avec les 0 principaux, de sorte que le tri lexicographique de data-type="text" donnera l'ordre alphanumérique correct.

Si vous utilisez le moteur XSLT de .NET, vous pouvez utiliser une fonction d'extension simple en C# pour les numéros de pad avec les 0.:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:myExt="urn:myExtension" 
       xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
       exclude-result-prefixes="msxsl myExt"> 
    <xsl:output method="xml" indent="yes" /> 

    <msxsl:script language="C#" implements-prefix="myExt"> 

    <![CDATA[ 
     private static string PadMatch(Match match) 
     { 
      // pad numbers with zeros to a maximum length of the largest int value 
      int maxLength = int.MaxValue.ToString().Length; 
      return match.Value.PadLeft(maxLength, '0'); 
     } 

     public string padNumbers(string text) 
     { 
      return System.Text.RegularExpressions.Regex.Replace(text, "[0-9]+", new System.Text.RegularExpressions.MatchEvaluator(PadMatch)); 
     } 
    ]]> 

    </msxsl:script> 
    <xsl:template match="/"> 
    <sorted> 
     <xsl:apply-templates select="colors/item"> 
     <xsl:sort select="myExt:padNumbers(label)" data-type="text" order="ascending"/> 
     </xsl:apply-templates> 
    </sorted> 
    </xsl:template> 

    <xsl:template match="item"> 
    <xsl:value-of select="label"/> 
    <xsl:if test="position() != last()">, </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 
+0

merci divo ... ouais je suppose que mon échantillon de données est un peu trop générique ;-) En réalité, il peut ne pas y avoir de délimiteur et/ou la position des chiffres pourrait être n'importe où. – scunliffe