我在实现排序时遇到了麻烦。我有一个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
。