当排序的元素有兄弟元素时,XSL排序



我在实现排序时遇到了麻烦。我有一个XML文档,除了将某些元素按顺序排序外,我想对其进行1对1的复制。为了根据模式进行验证,复制后的文档结构必须相同。我不能控制模式,所以我不能修改它。下面是我的XML数据的简化版本:

<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>

我想把<item>元素按特定的顺序排序。生成的XML文件应该是:

<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>

我成功地用以下XSL样式表进行了排序:

<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>

但是这是不令人满意的,因为我需要显式地处理<resHead><resFoot>,如果模式被扩展到包括<item>的其他兄弟,我将需要搜索这个XSL并修改它。我做了大量的研究,但只发现的例子,要么不包括任何兄弟元素或包含"排序"元素在一些"容器"元素,即:

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

我想找到一种更通用的方法来完成排序。我已经尝试了工作样式表的许多变体,但我要么丢失或重新定位兄弟节点,要么破坏排序。有人能帮忙吗?

<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>

如果您的所有item元素都是连续的,那么这里有一个解决方案:

<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>

它简单地将出现在第一个item元素之前的任何兄弟元素而不是resHead,以及出现在最后一个item元素之后的任何兄弟元素而不是resFoot

最新更新