更改XML元素顺序,同时保留结构层次结构和属性
我希望更改一些XML元素的顺序。XML是复杂的,并且是由一个单独的过程生成的——我不想更改它,所以我希望使用XSLT来纠正元素顺序 我不是XSLT专家(!),所以我查找了一些代码片段,找到了一些适合我的情况的小改动,几乎可以工作的东西。目前我拥有的最好的版本以正确的顺序输出元素,但去掉了所有属性 我创建了一个更简单的xml和相应的xsl,其中包含了问题的相关特性 以下是(虚拟)xml示例:更改XML元素顺序,同时保留结构层次结构和属性,xml,xslt,Xml,Xslt,我希望更改一些XML元素的顺序。XML是复杂的,并且是由一个单独的过程生成的——我不想更改它,所以我希望使用XSLT来纠正元素顺序 我不是XSLT专家(!),所以我查找了一些代码片段,找到了一些适合我的情况的小改动,几乎可以工作的东西。目前我拥有的最好的版本以正确的顺序输出元素,但去掉了所有属性 我创建了一个更简单的xml和相应的xsl,其中包含了问题的相关特性 以下是(虚拟)xml示例: <?xml version="1.0" encoding="UTF-8"?> <Comp
<?xml version="1.0" encoding="UTF-8"?>
<Companies xmlns="company:fruit:ns" Version="1.0">
<Description>Some example companies and fruit shipments</Description>
<Company CompanyId="Acme">
<Description>Some example shipments</Description>
<Shipment Id="ABC">
<Description>Some apples</Description>
<Fruit>
<Apples>10</Apples>
</Fruit>
</Shipment>
<Shipment Id="DEF">
<Description>Some oranges and pears</Description>
<Fruit>
<Oranges>20</Oranges>
<Pears>20</Pears>
</Fruit>
</Shipment>
<Shipment Id="JKL">
<Description>Empty</Description>
<Fruit/>
</Shipment>
<Fruit/>
</Company>
<Fruit/>
</Companies>
一些公司和水果运输的例子
一些示例装运
一些苹果
10
一些桔子和梨
20
20
空的
问题是,在Company Description元素之后应该有一个Company Fruit元素(而是在所有装运元素之后),在Companys Description元素之后应该有一个Companys Fruit元素(而是在所有Companys元素之后)。我使用以下xsl转换来更正元素顺序:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xpath-default-namespace="company:fruit:ns">
<!-- See http://xsltbyexample.blogspot.com/2008/02/re-arrange-order-of-elements-in-xml.html -->
<xsl:output omit-xml-declaration="no" indent="yes" method="xml" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:apply-templates select="self::*" mode="copy"/>
</xsl:template>
<xsl:template match="Company/Description">
<xsl:message>Matched Company Description</xsl:message>
<xsl:apply-templates select="self::*" mode="copy"/>
<xsl:apply-templates select="../Fruit" mode="copy"/>
</xsl:template>
<xsl:template match="Companies/Description">
<xsl:message>Matched Companies Description</xsl:message>
<xsl:apply-templates select="self::*" mode="copy"/>
<xsl:apply-templates select="../Fruit" mode="copy"/>
</xsl:template>
<xsl:template match="Company/Fruit"/>
<xsl:template match="Companies/Fruit"/>
<xsl:template match="*" mode="copy">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
匹配的公司描述
匹配公司描述
生成的xml具有正确的顺序,但大多数属性已被剥离:
<?xml version="1.0" encoding="utf-8"?>
<Companies xmlns="company:fruit:ns">
<Description>Some example companies and fruit shipments</Description>
<Fruit/>
<Company>
<Description>Some example shipments</Description>
<Fruit/>
<Shipment>
<Description>Some apples</Description>
<Fruit>
<Apples>10</Apples>
</Fruit>
</Shipment>
<Shipment>
<Description>Some oranges and pears</Description>
<Fruit>
<Apples>20</Apples>
<Pears>20</Pears>
</Fruit>
</Shipment>
<Shipment>
<Description>Empty</Description>
<Fruit/>
</Shipment>
</Company>
</Companies>
一些公司和水果运输的例子
一些示例装运
一些苹果
10
一些桔子和梨
20
20
空的
我欢迎来自XSLT专家的任何建议 应该保持几乎所有输入不变的转换最好从标识模板开始
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
然后相应地覆盖该模板
<!-- throw away <Fruit> elements, initially - they are handled separately -->
<xsl:template match="Company/Fruit | Companies/Fruit" />
<!-- re-build <Company> and <Companies> in the correct order -->
<xsl:template match="Company | Companies">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:copy-of select="Fruit" />
<xsl:apply-templates select="node()" />
</xsl:copy>
</xsl:template>
然后您就完成了。由@Tomalak提供的解决方案展示了如何重新排序元素,例如,
下的
元素不再跟随
元素。然而@Tomalak的解决方案将
元素放在
元素之前。顺序应该是
,
,,…
因此,为了完整起见,并且为了证明我从@Tomalak的解决方案(!)中学到了知识,xsl完整版本的相关部分如下所示:
<!-- throw away <Fruit> and <Description> elements, initially - they are handled separately -->
<xsl:template match="Company/Fruit | Companies/Fruit | Companies/Description | Company/Description"/>
<!-- re-build <Company> and <Companies> in the correct order -->
<xsl:template match="Company | Companies">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:copy-of select="Description"/>
<xsl:copy-of select="Fruit"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
再次感谢@Tomalak完成了繁重的工作…当您复制具有属性的元素时,只需使用
复制这些属性即可。这会将所有属性从当前节点复制到输出位置。您可以定义另一个与text()
匹配的模板,或者将该命令放入复制模式模板的
块中。@Matthias-感谢您的快速和有用的响应。我尝试了您所建议的更改,在xsl中的几个地方进行了尝试,但通常没有达到预期的效果。我可能误解了你的评论……感谢@Tomalak对你的清晰而有益的回复。不幸的是,它还不起作用。xslt处理器抱怨标识转换中出现运行时错误,表示在包含元素的子元素之后无法创建属性节点(版本)。哇,您使用的xslt处理器是什么?o_OA进一步-可能是次要的-问题可能是水果
元素也出现在每个装运
中,并且可能不应丢弃。这就是为什么我最初的xsl更具体地说明了要丢弃哪些元素。我应该解释在调用标识转换时会发生错误,而不是说标识转换本身有错!很抱歉给你带来困惑…谢谢@Tomalak-你是一个明星!它现在可以工作了,更棒的是,根据您的解决方案的结构,我理解它为什么可以工作。我将检查解决方案是否对我真正的问题有效——我相信它应该有效——然后能够将问题标记为已解决。再次感谢您的持续帮助:-)很高兴您也发布您的发现/自己的解决方案。坚持下去!:)