derehls
derehls

Reputation: 111

XSL sort elements depending on attribute with exception of specific elements

I already have a XSL that sorts my whole Document depending on the attribute values @id or @category. Now i want to enhance it by defining nodes that never should be sorted.

Here is a sample XML:

<root>
    [several levels of xml open]

    <elemetsToBeSorted>
        <sortMe id="8" />
        <sortMe id="2" />
        <sortMe id="4" />
    </elemetsToBeSorted>

    <elemetsNOTToBeSorted>
        <dontSortMe id="5" />
        <dontSortMe id="3" />
        <dontSortMe id="2" />
    </elemetsNOTToBeSorted>

    [several levels of xml closing]
</root>

This is my XSL:

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

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

<!-- Sort all Elements after their id or category -->
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()">
            <xsl:sort select="@id" />
            <xsl:sort select="@category" />
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>


<!-- Next two templates clean up formatting after sorting -->
<xsl:template match="text()[not(string-length(normalize-space()))]" />

<xsl:template match="text()[string-length(normalize-space()) > 0]">
    <xsl:value-of select="translate(.,'&#xA;&#xD;', '  ')" />
</xsl:template>

Expected Ouput:

<root>
    [several levels of xml open]

    <elemetsToBeSorted>
        <sortMe id="2" />
        <sortMe id="4" />
        <sortMe id="8" />
    </elemetsToBeSorted>

    <elemetsNOTToBeSorted>
        <dontSortMe id="5" />
        <dontSortMe id="3" />
        <dontSortMe id="2" />
    </elemetsNOTToBeSorted>

    [several levels of xml closing]
</root>

How can i achieve that my XSL ignores the "elementsNOTToBeSorted" ?

EDIT: I have hundreds of elements that should be sorted, but only a few elements (and its childs) that should not be sorted. So logic would be something like "sort all, except a and b"

Upvotes: 3

Views: 1646

Answers (2)

Pawel
Pawel

Reputation: 31610

Adding this line should ignore all descendants elements of elementsNOTToBeSorted:

<xsl:template match="elemetsNOTToBeSorted" />

if you want these elements still to be present in the output document you can just copy them instead of suppressing:

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

Upvotes: 0

Tomalak
Tomalak

Reputation: 338228

<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
</xsl:template>

<!-- all elements except a few sort their children -->
<xsl:template match="*[not(self::elemetsNOTToBeSorted | self::otherElemetsNOTToBeSorted)]">
    <xsl:copy>
        <xsl:apply-templates select="@*" />
        <xsl:apply-templates>
            <xsl:sort select="@id" />
            <xsl:sort select="@category" />
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

<!-- ... -->

Note that match expression specificity plays a role here. The more specific match expression determines which template will run:

  • node() is less specific than *, so element nodes will be handled by <xsl:template match="*">
  • elements matching self::elemetsNOTToBeSorted | self::otherElemetsNOTToBeSorted will be handled by the identity template.

Upvotes: 2

Related Questions