Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
更改XML元素顺序,同时保留结构层次结构和属性_Xml_Xslt - Fatal编程技术网

更改XML元素顺序,同时保留结构层次结构和属性

更改XML元素顺序,同时保留结构层次结构和属性,xml,xslt,Xml,Xslt,我希望更改一些XML元素的顺序。XML是复杂的,并且是由一个单独的过程生成的——我不想更改它,所以我希望使用XSLT来纠正元素顺序 我不是XSLT专家(!),所以我查找了一些代码片段,找到了一些适合我的情况的小改动,几乎可以工作的东西。目前我拥有的最好的版本以正确的顺序输出元素,但去掉了所有属性 我创建了一个更简单的xml和相应的xsl,其中包含了问题的相关特性 以下是(虚拟)xml示例: <?xml version="1.0" encoding="UTF-8"?> <Comp

我希望更改一些XML元素的顺序。XML是复杂的,并且是由一个单独的过程生成的——我不想更改它,所以我希望使用XSLT来纠正元素顺序

我不是XSLT专家(!),所以我查找了一些代码片段,找到了一些适合我的情况的小改动,几乎可以工作的东西。目前我拥有的最好的版本以正确的顺序输出元素,但去掉了所有属性

我创建了一个更简单的xml和相应的xsl,其中包含了问题的相关特性

以下是(虚拟)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>

一些公司和水果运输的例子
一些示例装运
一些苹果
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-你是一个明星!它现在可以工作了,更棒的是,根据您的解决方案的结构,我理解它为什么可以工作。我将检查解决方案是否对我真正的问题有效——我相信它应该有效——然后能够将问题标记为已解决。再次感谢您的持续帮助:-)很高兴您也发布您的发现/自己的解决方案。坚持下去!:)