Frage

Ich bin vor ein Problem, wo ich Elemente sortieren müssen, abhängig von deren Wert, die eine Zahl enthält, die durch Punkte getrennt. Ich brauche Elemente zu sortieren, in Abhängigkeit von dem Wert der Zahl vor dem ersten Periode, dann ist die Zahl zwischen dem ersten und zweiten Perioden und so weiter. Ich weiß nicht, wie tief diese Hierarchie gehen, und das ist das größte Problem.

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <ROW>2.0.1</ROW>
    <ROW>1.2</ROW>
    <ROW>1.1.1</ROW>
    <ROW>1.2.0</ROW>
    <ROW>1</ROW>
</root>

Das Ergebnis shoul so aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <ROW>1</ROW>
    <ROW>1.1.1</ROW>
    <ROW>1.2</ROW>
    <ROW>1.2.0</ROW>
    <ROW>2.0.1</ROW>
</root>

Ist das überhaupt möglich? Jede mögliche Hilfe schätzen.

War es hilfreich?

Lösung

gibt es eine „einfache“ Antwort, die keine Erweiterung nicht verwendet. Geteilten Zeilenwerte in Futter und Art auf sie

<xsl:template match="root">
    <xsl:copy>
        <xsl:apply-templates select="ROW">
            <xsl:sort select="substring-before(concat(., '.'), '.')" data-type="number"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>
<xsl:template match="ROW">
    <xsl:param name="prefix" select="''"/>
    <xsl:choose>
        <!-- end of recursion, there isn't any more ROW with more chucks -->
        <xsl:when test=". = substring($prefix, 1, string-length($prefix)-1)">
            <xsl:copy-of select="."/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:variable name="chuck" select="substring-before(concat(substring-after(., $prefix), '.'), '.')"/>
            <!-- this test is for grouping ROW with same prefix, to skip duplicates -->
            <xsl:if test="not(preceding-sibling::ROW[starts-with(., concat($prefix, $chuck))])">
                <xsl:variable name="new-prefix" select="concat($prefix, $chuck, '.')"/>
                <xsl:apply-templates select="../ROW[starts-with(., $new-prefix) or . = concat($prefix, $chuck)]">
                    <xsl:sort select="substring-before(concat(substring-after(., $new-prefix), '.'), '.')" data-type="number"/>
                    <xsl:with-param name="prefix" select="$new-prefix"/>
                </xsl:apply-templates>
            </xsl:if>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Andere Tipps

Das einzige Problem dies zu erreichen, ist mit einzelnen Nummern im Umgang (zwischen den Zeiträumen) unterschiedlicher Textlängen (d.h. Sortier 1,0, 2,0 und 10,0 in dieser Reihenfolge). Wenn es von der Größe der einzelnen Zahlen eine obere Grenze ist (n Ziffern sagen), dann einen Sortierschlüssel erzeugen, der die Verkettung aller Zahlen mit Nullen aufgefüllt, um n Stellen ist. Für n = 3, ergibt sich

Row               Key (string)
1                 001
1.0               001000
1.0.1             001000001
1.1               001001
1.2.1             001002001
2.0.1             002000001
10.0.1            010000001

Dann sortiert auf der Taste. Wenn Sie in XSLT 1.0 stecken werden Sie zurückgreifen Erweiterungsfunktionen EXSLT das Parsen und Schlüssel Normalisierung zu tun.

Es ist nicht schön, aber sie können die xalan verwenden: nodeset Funktion „Pre-Prozess“ die Zahlen in eine nodeset mit einem leicht sortierbar Ausdruck wie von Jim beschrieben.

Dieses Beispiel funktioniert für mich mit Xalan 2.5.1:

<?xml version="1.0"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:xalan="http://xml.apache.org/xalan">

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

<xsl:template match="/">
    <root>
        <!-- Create a sort node with a sort expression wrapping each ROW -->
        <xsl:variable name="nodes">
            <xsl:for-each select="/root/ROW">
                <xsl:variable name="sort-string">
                    <xsl:call-template name="create-sort-string">
                        <xsl:with-param name="sort-string" select="text()" />
                    </xsl:call-template>
                </xsl:variable>
                <sort sort-by="{$sort-string}">
                    <xsl:copy-of select="." />
                </sort>
            </xsl:for-each>
        </xsl:variable>

        <!-- Now sort the sort nodes and copy out the ROW elements -->
        <xsl:for-each select="xalan:nodeset($nodes)/sort">
            <xsl:sort select="@sort-by" data-type="text" />
            <xsl:copy-of select="*" />
        </xsl:for-each>
    </root>
</xsl:template>

<xsl:template name="create-sort-string">
    <xsl:param name="sort-string" />
    <!-- Biggest number at each level -->
    <xsl:variable name="max-num" select="1000" />
    <xsl:choose>
        <xsl:when test="contains($sort-string, '.')">
            <xsl:value-of select="$max-num + number(substring-before($sort-string, '.'))" />
            <xsl:call-template name="create-sort-string">
                <xsl:with-param name="sort-string" select="substring-after($sort-string, '.')" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="concat($max-num + number($sort-string), '0')" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Ich persönlich denke, das Schreiben eine Erweiterungsfunktion vorzuziehen wäre, aber ich weiß, das ist es nicht immer eine Option.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top