3 Stimmen

XSLT Benutzerdefinierte Sortierung

Ist es in XSLT möglich, in alphabetischer Reihenfolge zu sortieren, mit 5 Elementen als "bevorzugt".

d.h. gegeben

<teams>
<team id="142" name="Scotland" />
<team id="110" name="Liverpool" />
<team id="13" name="Manchester United" />
<team id="123" name="England" />
<team id="84" name="Chelsea" />
<team id="295" name="Wales" />
<team id="49" name="Arsenal" />
<team id="126" name="Northern Ireland" />
<team id="121" name="Republic of Ireland" />
<team id="42" name="Manchester City" />
<team id="298" name="Tottenham Hotspur" />
<team id="299" name="Bolton" />
</teams>

Ich verlange, dass die Nationalmannschaften zuerst in einer bestimmten Reihenfolge sortiert werden, gefolgt von den anderen in alphabetischer Reihenfolge:

<teams>
<team id="123" name="England" />
<team id="126" name="Northern Ireland" />
<team id="121" name="Republic of Ireland" />
<team id="142" name="Scotland" />
<team id="295" name="Wales" />
<team id="49" name="Arsenal" />
<team id="299" name="Bolton" />
<team id="84" name="Chelsea" />
<team id="110" name="Liverpool" />
<team id="42" name="Manchester City" />
<team id="13" name="Manchester United" />
<team id="298" name="Tottenham Hotspur" />
</teams>

Ich habe es versucht, bin aber gescheitert.

Gibt es eine einfache Möglichkeit, dies zu tun, oder müssen Sie die Nationalmannschaften einzeln sortieren, gefolgt von einer Sortierung, die alle Nationalmannschaften ausschließt?

12voto

Dirk Vollmar Punkte 166522

Tim C hat bereits eine gute Antwort gegeben, aber vielleicht reicht in Ihrem Fall eine einfachere Methode aus. Sie könnten einfach zwei xsl:sort Bedingungen: Bei der ersten wird nach bevorzugten/nicht bevorzugten Artikeln sortiert, bei der zweiten alphabetisch nach Namen:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/teams">
    <teams>
      <xsl:for-each select="team">
        <xsl:sort select="not(@name = 'England' or @name='Northern Ireland'
                           or @name='Republic of Ireland' 
                           or @name='Scotland' or @name='Wales')" 
                  data-type="number"/>
        <xsl:sort select="@name"/>
        <team>
          <xsl:value-of select="@name"/>
        </team>
      </xsl:for-each>
    </teams>
  </xsl:template>
</xsl:stylesheet>

Bitte beachten Sie, dass Sie die erste Bedingung mit not() . Der Grund dafür ist, dass das boolesche Ergebnis Ihres Ausdrucks in eine Zahl umgewandelt wird (0 ist falsch, 1 ist wahr) und daher die Elemente, die als "falsch" ausgewertet werden, zuerst aufgeführt werden.

6voto

Tomalak Punkte 320467

Sie könnten dies tun:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:my="http://tempuri.org"
  exclude-result-prefixes="my"
>

  <xsl:output method="xml" indent="yes" /> 

  <my:data>
    <my:nationalteams>
      <my:team id="121" /><!-- Republic of Ireland -->
      <my:team id="123" /><!-- England -->
      <my:team id="126" /><!-- Northern Ireland -->
      <my:team id="142" /><!-- Scotland -->
      <my:team id="295" /><!-- Wales -->
    </my:nationalteams>
  </my:data>

  <xsl:template match="teams">
    <xsl:copy>
      <xsl:variable name="national" select="
        document('')/*/my:data/my:nationalteams/my:team
      " />
      <!-- national teams preferred -->
      <xsl:apply-templates select="team[@id = $national/@id]">
        <xsl:sort select="@name" />
      </xsl:apply-templates>
      <!-- other teams after them -->
      <xsl:apply-templates select="team[not(@id = $national/@id)]">
        <xsl:sort select="@name" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="team">
    <xsl:copy-of select="." />
  </xsl:template>

</xsl:stylesheet>

Die gesamte <my:data> könnte in eine sekundäre XML/Konfigurationsdatei verschoben werden, in der auch der Namensraum "my" weggelassen werden kann.

Danach würde eine Zeile eine kleine Änderung benötigen:

<xsl:variable name="national" select="
  document('config.xml')/data/nationalteams/team
" />

Das Ergebnis der obigen Ausführungen ist wenig überraschend :-)

<teams>
  <team id="123" name="England" />
  <team id="126" name="Northern Ireland" />
  <team id="121" name="Republic of Ireland" />
  <team id="142" name="Scotland" />
  <team id="295" name="Wales" />
  <team id="49" name="Arsenal" />
  <team id="299" name="Bolton" />
  <team id="84" name="Chelsea" />
  <team id="110" name="Liverpool" />
  <team id="42" name="Manchester City" />
  <team id="13" name="Manchester United" />
  <team id="298" name="Tottenham Hotspur" />
</teams>

2voto

Tim C Punkte 69030

Können Sie in Ihrem XSLT die Erweiterungsfunktionen nutzen?

Wenn dies der Fall ist, besteht eine Methode darin, die bestehende Liste der Knoten inline zu ändern, um eine neue Knotenmenge zu erstellen, jedoch mit einem zusätzlichen Attribut "sortname" für jeden Knoten. Sie können dann durch diesen neuen Knotensatz iterieren und anhand des neuen Attributs "sortname" sortieren:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="urn:schemas-microsoft-com:xslt">
    <xsl:output method="xml" />
    <xsl:template match="/teams">
        <xsl:variable name="extendedteams">
        <xsl:for-each select="team">
            <xsl:copy>
                <xsl:copy-of select="@*" />
                <xsl:attribute name="sortname">
                    <xsl:choose>
                        <xsl:when test="@name='England' or @name='Northern Ireland' or @name='Republic of Ireland' or @name='Scotland' or @name='Wales'">1</xsl:when>
                        <xsl:otherwise>2</xsl:otherwise>
                    </xsl:choose>
                    <xsl:value-of select="@name" />
                </xsl:attribute>
            </xsl:copy>
        </xsl:for-each>
        </xsl:variable>
        <xsl:copy>
        <xsl:for-each select="exsl:node-set($extendedteams)/team">
            <xsl:sort select="@sortname" />

            <xsl:copy>
                <xsl:copy-of select="@*[name() != 'sortname']" />
            </xsl:copy>
        </xsl:for-each>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Im obigen Beispiel setze ich eine "1" vor eine beliebige Nationalmannschaft und eine "2" vor eine beliebige Nationalmannschaft und sortiere dann nach diesem neuen Attribut.

Siehe Informationen auf Knotenpunktsätze um zu sehen, welche XSLT-Prozessoren welche Erweiterungen unterstützen.

1voto

Dewfy Punkte 22558

Haben Sie das Element xsl:sort gesehen? Sie können zwei oder mehr Sortierkriterien erstellen, indem Sie xsl:apply-templates und xsl:sort kombinieren

Hier ist in der Tat ein Beispiel, bei dem einige Länder in einer vordefinierten Reihenfolge an erster Stelle stehen, dann alle anderen. Beachten Sie, dass es sich dabei um Elemente handelt, nicht um Attribute wie oben.

<xsl:sort select="not(CountryValue = 'Scotland')"/>
<xsl:sort select="not(CountryValue = 'India')"/>
<xsl:sort select="CountryValue"/>

Ergebnis der Probe:

Land

Scotland   
Scotland 
Scotland 
India 
Afghanistan 
Afghanistan 
Afghanistan 
Afghanistan 
Afghanistan 
Afghanistan 
Albania 
Albania 
Albania 
Algeria

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X