开发者

XSL sort when sorted elements have siblings

开发者 https://www.devze.com 2023-03-24 21:23 出处:网络
I am having trouble implementing a sort. I have an XML document that I want to do a 1 for 1 copy except sort certain elements into order. The structure of the document must be the same after the copy

I am having trouble implementing a sort. I have an XML document that I want to do a 1 for 1 copy except sort certain elements into order. The structure of the document must be the same after the copy in order to validate against the schema. I am not in control of the schema so I cannot modify it. Here is a simplified version of my XML data:

<ResponseDoc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <resHead>
        <id>R1983Rs</id>
    </resHead>
    <item>
        <objRef>
            <objId>100</objId>
            <sysId>xyz</sysId>
        </objRef>
        <!-- Additional data here -->
    </item>
    <item>
        <objRef>
            <objId>140</objId>
            <sysId>abc</sysId>
        </objRef>
        <!-- Additional data here -->
    </item>
    <resFoot>
        <id>1234</id>
    </resFoot>
</ResponseDoc>

I want to sort the <item> elements into a specific order. The resulting XML file should be:

<ResponseDoc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <resHead>
        <id>R1983Rs</id>
    </resHead>
    <item>
        <objRef>
            <objId>140</objId>
            <sysId>abc</sysId>
        </objRef>
        <!-- Additional data here -->
    </item>
    <item>
        <objRef>
            <objId>100</objId>
            <sysId>xyz</sysId>
        </objRef>
        <!-- Additional data here -->
    </item>
    <resFoot>
        <id>1234</id>
    </resFoot>
</ResponseDoc>

I was successful in sorting with the following XSL stylesheet:

<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />
    <xsl:template match="ResponseDoc">
        <xsl:copy>
            <xsl:apply-templates select="resHead" />
            <xsl:apply-templates select="item">
                <xsl:sort select="number(objRef/objId)" order="descending" />
            </xsl:apply-templates>
            <xsl:apply-templates select="resFoot" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

But this is unsatisfying since I need to explicitly handle <resHead> and <resFoot> and if the schema is expanded to include additional sibling(s) to <item>, I will need to search out this XSL and modify it. I have done a great deal of research but only find examples that either don't i开发者_运维百科nclude any sibling elements OR contain the "sorted" elements within some "container" element, i.e.:

...
<items>
    <item>...</item>
    <item>...</item>
    <item>...</item>
</items>
...

I'd like to find more generic way of accomplishing the sort. I've attempted many varients of the working style sheet but I either lose or reposition the sibling nodes or break the sort. Can anyone help out?


<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />

    <xsl:template match="/">

    <xsl:for-each select="ResponseDoc">
       <xsl:sort select="item"  order="descending" />

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

     </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>


Here's a solution that will work if all your item elements are contiguous:

<xsl:template match="ResponseDoc">
    <xsl:copy>
        <xsl:apply-templates select="item[1]/preceding-sibling::*" />
        <xsl:apply-templates select="item">
            <xsl:sort select="number(objRef/objId)" order="descending" />
        </xsl:apply-templates>
        <xsl:apply-templates select="item[last()]/following-sibling::*" />
    </xsl:copy>
</xsl:template>

It simply species any siblings that come before the first item element instead of resHead, and any siblings that come after the last item element instead of resFoot.

0

精彩评论

暂无评论...
验证码 换一张
取 消