Gern stehe ich zur fachlichen Unterstützung in XML-Technologien, C#.NET, VisualBasic.NET und Java zur Verfügung. Sprechen Sie mich einfach an: Mail oder ☎ 0151 . 750 360 61


XSL-Übersicht / xsl:sort, xsl:perform-sort, fn:sort

xsl:sort, xsl:perform-sort, fn:sort

xsl:sort, xsl:perform-sort, fn:sort

➪ Eine häufige Aufgabe ist das Sortieren von Ergebnissen. Hier finden Sie in xsl:sort, xsl:perform-sort und fn:sort leistungsfähige Unterstützung.

Auf dieser Seite:

Schauen Sie sich zunächst die Logik ohne Sortierung an.


<xsl:for-each select="//Gehalt">
    <einkommen>
        <xsl:value-of select="."/>
    </einkommen>
</xsl:for-each>

Das (noch unsortierte) Ergebnis sieht so aus:


<einkommen>234.56</einkommen>
<einkommen>1234.56</einkommen>
<einkommen>5430</einkommen>
<einkommen>321.45</einkommen>
<einkommen>987.58</einkommen>
<einkommen>654.21</einkommen>
<einkommen>333.33</einkommen>
<einkommen>456</einkommen>
<einkommen>876.54</einkommen>
<einkommen>546.77</einkommen>
<einkommen>777.77</einkommen>
<einkommen>357</einkommen>
<einkommen>6789</einkommen>
<einkommen>234</einkommen>
<einkommen>321</einkommen>
<einkommen>456</einkommen>
<einkommen>3450</einkommen>
<einkommen>222</einkommen>
<einkommen>135</einkommen>

Sortierungen mit xsl:sort

Nun erfolgt die Sortierung mit xsl:sort. Da die Default-Sortierung data-type="text" ist, muss der Prozessor angewiesen werden, die Einzelwerte als number zu erkennen. order="descending definiert die absteigende Sortierung, Alternative: order="ascending".


<xsl:for-each select="//Gehalt">
  <xsl:sort 
       select="." 
       data-type="number" 
       order="descending"/>
  <einkommen>
        <xsl:value-of select="."/>
  </einkommen>
</xsl:for-each>

Ich denke, das Ergebnis ist nachvollziehbar:


<einkommen>6789</einkommen>
<einkommen>5430</einkommen>
<einkommen>3450</einkommen>
<einkommen>1234.56</einkommen>
<einkommen>987.58</einkommen>
<einkommen>876.54</einkommen>
<einkommen>777.77</einkommen>
<einkommen>654.21</einkommen>
<einkommen>546.77</einkommen>
<einkommen>456</einkommen>
<einkommen>456</einkommen>
<einkommen>357</einkommen>
<einkommen>333.33</einkommen>
<einkommen>321.45</einkommen>
<einkommen>321</einkommen>
<einkommen>234.56</einkommen>
<einkommen>234</einkommen>
<einkommen>222</einkommen>
<einkommen>135</einkommen>

Sortierungen mit fn:sort

Nun gibt es auch die Möglichkeit, die Sortierung direkt in XPath aufzurufen:


<xsl:for-each select="sort(//Gehalt)">
    <einkommen>
        <xsl:value-of select="."/>
    </einkommen>
</xsl:for-each>

Per Default wird dabei jedes Item als Text angesehen, daher fällt das Sortierergebnis vorläufig so aus:


<einkommen>1234.56</einkommen>
<einkommen>135</einkommen>
<einkommen>222</einkommen>
<einkommen>234</einkommen>
<einkommen>234.56</einkommen>
<einkommen>321</einkommen>
<einkommen>321.45</einkommen>
<einkommen>333.33</einkommen>
<einkommen>3450</einkommen>
<einkommen>357</einkommen>
<einkommen>456</einkommen>
<einkommen>456</einkommen>
<einkommen>5430</einkommen>
<einkommen>546.77</einkommen>
<einkommen>654.21</einkommen>
<einkommen>6789</einkommen>
<einkommen>777.77</einkommen>
<einkommen>876.54</einkommen>
<einkommen>987.58</einkommen>

Durch ein einfaches Type-Casting auf xs:decimal wird jedes Item als Zahl anerkannt ...


<xsl:for-each select="sort(//xs:decimal(Gehalt))">
    <einkommen>
        <xsl:value-of select="."/>
    </einkommen>
</xsl:for-each>

... und entsprechend sortiert:


<einkommen>135</einkommen>
<einkommen>222</einkommen>
<einkommen>234</einkommen>
<einkommen>234.56</einkommen>
<einkommen>321</einkommen>
<einkommen>321.45</einkommen>
<einkommen>333.33</einkommen>
<einkommen>357</einkommen>
<einkommen>456</einkommen>
<einkommen>456</einkommen>
<einkommen>546.77</einkommen>
<einkommen>654.21</einkommen>
<einkommen>777.77</einkommen>
<einkommen>876.54</einkommen>
<einkommen>987.58</einkommen>
<einkommen>1234.56</einkommen>
<einkommen>3450</einkommen>
<einkommen>5430</einkommen>
<einkommen>6789</einkommen>

Die absteigende Sortierung ist Ihnen lieber? Bitte sehr, mit funktioniert auch das:


<xsl:for-each select="reverse(sort(//xs:decimal(Gehalt)))">
    <einkommen>
        <xsl:value-of select="."/>
    </einkommen>
</xsl:for-each>

Funktionsbasierte Sortierungen mit fn:sort

Ergänzend gibt es die Möglichkeit, durch Einsatz von anonymen Funktionen den Sortierungsschlüssel zu verändern.

Die im Folgenden implementierte Funktion multipliziert den jeweiligen Dezimalwert mit 10, wenn er ursprünglich unter 300 lag.


<xsl:for-each 
     select="sort(//xs:decimal(Gehalt), '',  
     function($v){ if ($v &lt; 300 ) 
                   then ( $v * 10 ) 
                   else ( $v ) })">
    <einkommen>
        <xsl:value-of select="."/>
    </einkommen>
</xsl:for-each>

Dadurch erhalten die Einzelwerte einen effektiven internen Sortierwert in Höhe von:


   135    -> 1350
   222    -> 2220
   234    -> 2340
   234.56 -> 2345.6

... und das führt letztlich zu einem modifizierten Ergebnis:


<einkommen>321</einkommen>
<einkommen>321.45</einkommen>
<einkommen>333.33</einkommen>
<einkommen>357</einkommen>
<einkommen>456</einkommen>
<einkommen>456</einkommen>
<einkommen>546.77</einkommen>
<einkommen>654.21</einkommen>
<einkommen>777.77</einkommen>
<einkommen>876.54</einkommen>
<einkommen>987.58</einkommen>
<einkommen>1234.56</einkommen>
<einkommen>135</einkommen>
<einkommen>222</einkommen>
<einkommen>234</einkommen>
<einkommen>234.56</einkommen>
<einkommen>3450</einkommen>
<einkommen>5430</einkommen>
<einkommen>6789</einkommen>

Textbasierte Sortierung mit Collations

Bei der textbasierten Sortierung können eine wichtige Rolle spielen. Freilich akzeptiert nicht jeder Prozessor die Collation http://www.w3.org/2013/collation/UCA?lang=de;strength=primary. Hier bietet sich das lang-Attribut von xsl:sort an.


 <xsl:template name="sortByCollation">
  <xsl:variable name="vfeld">
   <i>Straße2</i>
   <i>Strasse1</i>
   <i>Weg</i>
   <i>Straße1</i>
   <i>Strasse2</i>
   <i>Pfad</i>
  </xsl:variable>
  <xsl:for-each select="$vfeld/i">
   <xsl:sort select="." lang="de"/>
   <!-- anstelle von
   <xsl:sort 
        select="."  
        collation="...s.o. "/>
   -->
   <y>
    <xsl:value-of select="."/>
   </y>
  </xsl:for-each>
 </xsl:template>

Und hiermit erfolgt auch diese Sortierung korrekt:


<root>
   <y>Pfad</y>
   <y>Strasse1</y>
   <y>Straße1</y>
   <y>Straße2</y>
   <y>Strasse2</y>
   <y>Weg</y>
</root>

Sortierungen mit xsl:perform-sort

Natürlich ist es auch möglich, mehrere Sortierungen durchzuführen; im Beispiel fülle ich eine Variable v1 mit einer sortierten Sequenz.


<xsl:variable name="v1">    
  <xsl:for-each 
       select="//Mensch">
    <xsl:sort 
         select="../name" 
         data-type="text" 
         order="descending"/>
    <xsl:sort 
         select="Gehalt" 
         data-type="number" 
         order="ascending"/>
    <xsl:sequence select="."/>
  </xsl:for-each>
</xsl:variable>

Alternativ können Sie ab XSLT Version 2.0 dieselbe Sortierung auch mit xsl:perform-sort durchführen, auch ohne Verwendung von xsl:for-each oder xsl:apply-templates.


<xsl:variable name="v2">
  <xsl:perform-sort 
       select="//Mensch">
    <xsl:sort 
         select="../name" 
         data-type="text" 
         order="descending"/>
    <xsl:sort 
         select="Gehalt" 
         data-type="number" 
         order="ascending"/>
  </xsl:perform-sort>
</xsl:variable>

wg / 1. April 2018



Fragen? Anmerkungen? Tipps?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/XSL_XPATH_sort.html