Announcement

Collapse
No announcement yet.

XSL: Sortiere Knoten zur Laufzeit

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • XSL: Sortiere Knoten zur Laufzeit

    Guten Abend!

    Ausgangssituation:
    Im XML-Dokument gibt es in einem Element (bis zu) vier Kinder. Die haben alle ein Attribut "source".
    Im XML-Dokument sind die vier Element wild durcheinander notiert.
    Also etwa
    Code:
    <element source="xx"/>
    <element source="ff"/>
    <element source="aa"/>
    <element source="gg"/>
    In der XSL-Transformation will ich diese bis zu vier Kinder der Reihe nach abarbeiten. Und zwar in der alphabetischen Reihenfolge des source-Attributs.
    Zuerst soll (im Beispiel) das Element mit source="aa" abgearbeitet werden, dann das mit "ff" und so weiter.

    Problem:
    Wenn ich mittels
    Code:
    <xsl:sort select="@source"/>
    sortiere, hat das (für mich) keine Auswirkungen. (Steht auch überall: Sortiert nur den Output.) Wenn ich nämlich danach mit
    Code:
     <xsl:when test="position()=1">
    das erste Element anspreche, ist erhalte ich eben nicht das Element mit source="aa", sondern dasjenige, das im Ausgangsdokument als erstes notiert ist, also in meinem Beispiel das Element mit source="xx".

    Wie löse ich dieses Problem? Wie kann ich in XSLT die Elemente in alphabetischer Reihenfolge nach einem Attribut ansprechen?

  • #2
    Wo steht denn das xsl:sort-Element? Es kann unterhalb von xsl:for-each, xsl:for-each-group und xsl:apply-templates stehen. Dieses Beispiel gibt auch problemlos "aa" aus:
    [highlight=xml]<xsl:for-each select="element">
    <xsl:sort select="@source"/>
    <xsl:if test="position()=1">
    <xsl:value-of select="@source"/>
    </xsl:if>
    </xsl:for-each>[/highlight]
    Hinweis: order steht per Default auf "ascending" (bzw. "descending") und data-type auf "text" (bzw. "number").

    Comment


    • #3
      Sorry, sorry. Ich hab mich mal wieder in meinem eigenen Code verlaufen.

      Das Problem ist nicht die position-Abfrage, sondern der Zugriff über die Position mittels eckiger Klammern. Also "element[3]" soll "<element source="gg"/>" liefern. (Weil alphabetisch an dritter Stelle.) Und das tut nicht. Zumindest bei mir nicht.

      Comment


      • #4
        Die Dokumentordnung wird ja auch nicht verändert. Alternativ unter XSLT 2.0 die Daten sortiert in eine Sequenz legen und dann auf ihre Mitglieder zugreifen (test als Wurzelelement verwendet):
        [highlight=XML]<?xml version="1.0" encoding="UTF-8"?>
        <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">

        <xsl:template match="test">

        <xsl:variable name="elem" as="xs:string*">
        <xsl:for-each select="element">
        <xsl:sort select="@source"/>
        <xsl:value-of select="@source"/>
        </xsl:for-each>
        </xsl:variable>

        <xsl:value-of select="$elem[3]"/><!-- gg -->

        </xsl:template>

        </xsl:stylesheet>[/highlight]
        Ansonsten mal das Problem genauer schildern, es gibt vermutlich andere sinnvolle Lösungen.

        Comment


        • #5
          Vielen Dank für deine Mühen,

          aber das tut leider auch nicht, was ich will.

          Das sortiert ja nur die Werte der "source"-Eigenschaft. Ich brauch aber auch Zugriff auf alle anderen Eigenschaften des jeweiligen Elements. Dass mein Element noch andere Attribute hat, hab ich der Einfachheit halber nicht erwähnt, aber dadurch die Sache nur verkompliziert.

          Also nochmal anders formuliert:
          Ich will meine Elemente vom Typ "element" alphabetisch nach ihrer "source"-Eigenschaft sortieren und danach im weiteren Code alles mit diesen nun nach "source" sortieren Elementen machen, was man in XSLT mit Elementen so alles machen kann: Eigenschaften auslesen, Inhalt ausgeben, durch for-each-Schleifen jagen, Child, Parent, Sibling ansprechen etc.

          Da muss es doch eine Lösung geben.

          Gut, die einfachste Lösung wäre, die Dinger schon im Ausgangselement alphabetisch zu sortieren. Alternativ könnte man natürlich ein "Zwischendokument" kreieren: Genau gleich wie das Ausgangsdokument nur mit sortierten Elementen. Aber es muss doch eine einfache Lösung geben.

          Comment


          • #6
            Mit XSLT 2.0 lässt sich ein solches "Zwischendokument" erzeugen und ansprechen:
            [Highlight=XML]<xsl:template match="test">

            <xsl:variable name="mydoc" as="document-node()">
            <xsl:document>
            <wurzel>
            <xsl:for-each select="element">
            <xsl:sort select="@source"/>
            <xsl:copy-of select="."/>
            </xsl:for-each>
            </wurzel>
            </xsl:document>
            </xsl:variable>

            <xsl:value-of select="$mydoc/wurzel/element[3]/@source"/><!-- gg -->

            </xsl:template>[/Highlight]

            Comment


            • #7
              Vielen herzlichen Dank!

              Wusste nicht, dass das so einfach geht, also ohne etwa das "Zwischendokument" zu speichern. Ein neues Stylesheet zu erzeugen, das das Zwischendokument bearbeitet etc.

              Das ist das wohl, was ich suchte.

              Comment

              Working...
              X