Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.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
XSLT-复制重新排序的子代_Xslt - Fatal编程技术网

XSLT-复制重新排序的子代

XSLT-复制重新排序的子代,xslt,Xslt,我对XSLT非常陌生,我试图复制一个已经存在的XML文件,但元素被重新排序,但我在尝试重新排序子元素时遇到了问题 假设我有这个输入: <grandParent> <parent> <c>789</c> <b> <b2>123</b2> <b1>456</b1> </b>

我对XSLT非常陌生,我试图复制一个已经存在的XML文件,但元素被重新排序,但我在尝试重新排序子元素时遇到了问题

假设我有这个输入:

<grandParent>
    <parent> 
        <c>789</c>
        <b>
           <b2>123</b2>
           <b1>456</b1>
        </b>
        <a>123</a>
    </parent>
    ....
</grandParent>

789
123
456
123
....
我想做的是得到相同的XML文件,但将标记的顺序更改为a、b、c,b=b1、b2。 所以我从XSLT文件开始:

<xsl:template match="node()|@*">    <- This should copy everything as it is
    <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
</xsl:template>
<xsl:template match="grandParent/parent"> <- parent elements will copy in this order
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:copy-of select="a"/>
        <xsl:copy-of select="b"/>
        <xsl:copy-of select="c"/>
    </xsl:copy>
</xsl:template>
使用

下面的代码是我脑子里想不出来的,可能不起作用;不过,背后的想法应该是清楚的

<xsl:template match="node()|@*">    <- This should copy everything as it is
    <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
</xsl:template>

<xsl:template match="grandParent/parent"> <- parent elements will copy in this order
    <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:copy-of select="a"/>
    <b>
        <xsl:for-each select="b/*">
            <xsl:sort select="text()" />
            <xsl:copy-of select="." />
        </xsl:for-each>
    </b>
    <xsl:copy-of select="c"/>
    </xsl:copy>
</xsl:template>

我尝试使用另一个xsl:template作为“祖父母/parent/b”,但没有帮助

因为您有一个身份模板,所以应该使用
而不是

这将很好地处理
b
不存在的情况-如果
select=“b”
找不到任何元素,则不会触发任何模板

事实上,如果两种情况下的排序顺序相同(按元素名称的字母顺序),那么您可以将两个模板组合成一个使用
的模板,从而完成

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:strip-space elements="*" />
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="node()|@*">
    <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="grandParent/parent | parent/b">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="*">
        <xsl:sort select="name()" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>


(对于您给出的示例XML,您实际上不需要
@*
位,因为XML不包含任何属性,但如果真实XML中存在任何属性或您将来添加任何属性,将其保留在那里不会有任何伤害).

这里有一个最通用的解决方案--使用
xsl:sort
和模板--没有
xsl:copy of
和特定名称的硬编码

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="*/*">
     <xsl:copy>
       <xsl:apply-templates select="@*"/>
       <xsl:apply-templates select="node()">
         <xsl:sort select="name()"/>
       </xsl:apply-templates>
     </xsl:copy>
 </xsl:template>
</xsl:stylesheet>
<grandParent>
   <parent>
      <a>123</a>
      <b>
         <b1>456</b1>
         <b2>123</b2>
      </b>
      <c>789</c>
   </parent>
    ....
</grandParent>
<someGrandParent>
    <someParent>
        <z>789</z>
        <y>
            <y2>123</y2>
            <y1>456</y1>
        </y>
        <x>123</x>
    </someParent>
    ....
</someGrandParent>

在提供的XML文档上应用此转换时:

<grandParent>
    <parent>
        <c>789</c>
        <b>
            <b2>123</b2>
            <b1>456</b1>
        </b>
        <a>123</a>
    </parent>
    ....
</grandParent>
<someGrandParent>
   <someParent>
      <x>123</x>
      <y>
         <y1>456</y1>
         <y2>123</y2>
      </y>
      <z>789</z>
   </someParent>
    ....
</someGrandParent>

789
123
456
123
....
生成所需的正确结果

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="*/*">
     <xsl:copy>
       <xsl:apply-templates select="@*"/>
       <xsl:apply-templates select="node()">
         <xsl:sort select="name()"/>
       </xsl:apply-templates>
     </xsl:copy>
 </xsl:template>
</xsl:stylesheet>
<grandParent>
   <parent>
      <a>123</a>
      <b>
         <b1>456</b1>
         <b2>123</b2>
      </b>
      <c>789</c>
   </parent>
    ....
</grandParent>
<someGrandParent>
    <someParent>
        <z>789</z>
        <y>
            <y2>123</y2>
            <y1>456</y1>
        </y>
        <x>123</x>
    </someParent>
    ....
</someGrandParent>

123
456
123
789
....
现在,让我们更改XML文档中的所有名称——请注意,其他答案都不适用于此

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="*/*">
     <xsl:copy>
       <xsl:apply-templates select="@*"/>
       <xsl:apply-templates select="node()">
         <xsl:sort select="name()"/>
       </xsl:apply-templates>
     </xsl:copy>
 </xsl:template>
</xsl:stylesheet>
<grandParent>
   <parent>
      <a>123</a>
      <b>
         <b1>456</b1>
         <b2>123</b2>
      </b>
      <c>789</c>
   </parent>
    ....
</grandParent>
<someGrandParent>
    <someParent>
        <z>789</z>
        <y>
            <y2>123</y2>
            <y1>456</y1>
        </y>
        <x>123</x>
    </someParent>
    ....
</someGrandParent>

789
123
456
123
....
我们应用相同的转换,它再次产生正确的结果:

<grandParent>
    <parent>
        <c>789</c>
        <b>
            <b2>123</b2>
            <b1>456</b1>
        </b>
        <a>123</a>
    </parent>
    ....
</grandParent>
<someGrandParent>
   <someParent>
      <x>123</x>
      <y>
         <y1>456</y1>
         <y2>123</y2>
      </y>
      <z>789</z>
   </someParent>
    ....
</someGrandParent>

123
456
123
789
....

两种解决方案都有效。但在我看来,这个更整洁。谢谢你们,IanIan,存在一个更通用的解决方案,它适用于每个XML文档——不依赖于任何名称。但在我看来,伊恩的解决方案更整洁。无论如何,谢谢你!嗨,迪米特里,首先谢谢你的回答。当然,您的解决方案适用于此场景。但是如果我没弄错的话,只有当名字相互关联时,它才会起作用。我举了一个例子,这些名字只是为了缩写。但在我的现实生活场景中,这个解决方案行不通。@drewich,你还没有理解这个解决方案。它不做任何假设!你所说的“相关”名称是什么意思?????很抱歉反应太晚。嗯,有可能是我不理解解决方案。据我所知,“”会按标签名称的字母顺序对标签进行排序,对吗?我是XSLT的新手,所以我可能不理解它。@drewich,是的。这就是xsl:sort的定义方式。如果我的XML看起来像:并且我希望结果是:你的建议行不通。这就是我的意思,如果所需的顺序是字母顺序,那么您的解决方案就可以工作。但那不是我的真实情况。当然,感谢您的解决方案和意见