更改 XML 元素顺序,同时保持结构层次结构和属性 [英] Change XML element ordering while keeping structural hierarchy and attributes
问题描述
我希望更改一些 XML 元素的顺序.XML 很复杂,并且由单独的过程生成 - 我不需要对其进行更改,因此我希望使用 XSLT 来纠正元素顺序.
I wish to change the order of some XML elements. The XML is complex and generated by a separate process - I am not fee to change it, so I was hoping to use XSLT to correct the element order.
我不是 XSLT 专家(!),所以我查找了一些片段并找到了一些内容,只需稍加改动以适应我的情况,几乎就可以工作.我目前最好的版本以正确的顺序输出元素,但去掉了所有的属性.
I am not an XSLT expert(!) so I looked for some snippets and found something that, with minor changes to suit my case, almost works. The best version I have at present outputs elements in the correct order, but strips out all the attributes.
我用我的问题的相关特性创建了一个更简单的 xml 和相应的 xsl.
I created a simpler xml and corresponding xsl with the relevant features of my problem.
这是(虚拟的)示例 xml:
Here is the (dummy) example xml:
<?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>
问题是在 Company-Description 元素之后应该有一个 Company-Fruit 元素(而不是跟在所有 Shipment 元素之后),并且在 Companies-Description 元素之后应该有一个 Companies-Fruit 元素(而不是跟在所有 Shipment 元素之后)公司 - 公司要素).我使用以下 xsl 转换来更正元素排序:
The problem is that there should be a Company-Fruit element following the Company-Description element (instead it follows all the Shipment elements) and there should be a Companies-Fruit element following the Companies-Description element (instead it follows all the Companies-company elements). I used the following xsl transformation to correct the element ordering:
<?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 具有正确的顺序,但大部分属性已被删除:
The resulting xml has the right ordering but most of the attributes have been stripped out:
<?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>
我欢迎来自 XSLT 专家的任何建议!
I would welcome any advice from the XSLT experts out there!
推荐答案
应该保持几乎所有输入不变的转换最好从标识模板开始.
Transformations that should keep nearly all the input unchanged are best started with the identity template.
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
然后相应地覆盖该模板.
Then you override that template accordingly.
<!-- 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>
然后你就完成了.
这篇关于更改 XML 元素顺序,同时保持结构层次结构和属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!