XSLT-复制重新排序的子代
我对XSLT非常陌生,我试图复制一个已经存在的XML文件,但元素被重新排序,但我在尝试重新排序子元素时遇到了问题 假设我有这个输入:XSLT-复制重新排序的子代,xslt,Xslt,我对XSLT非常陌生,我试图复制一个已经存在的XML文件,但元素被重新排序,但我在尝试重新排序子元素时遇到了问题 假设我有这个输入: <grandParent> <parent> <c>789</c> <b> <b2>123</b2> <b1>456</b1> </b>
<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看起来像:并且我希望结果是:你的建议行不通。这就是我的意思,如果所需的顺序是字母顺序,那么您的解决方案就可以工作。但那不是我的真实情况。当然,感谢您的解决方案和意见