我对XSLT很陌生,我试图复制一个已有的XML文件,但重新排序的元素却在试图重新排序孙子时遇到困难。
假设我有这样的意见:
<grandParent>
<parent>
<c>789</c>
<b>
<b2>123</b2>
<b1>456</b1>
</b>
<a>123</a>
</parent>
....
</grandParent>
我想要做的是获取相同的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:copy-of select =”b“”复制指定的元素(b2,b1)。 我尝试使用另一个xsl:template“grandParent / parent / b”,但没有帮助。
也许我没有按照正确的方式做事......有什么提示吗?
谢谢!
解决方案 - 感谢Nils
你的解决方案可以很好地运行Nils,我只是对它进行了一些调整以适应我当前的情况,其中“b”是可选的,并且标签的名称可能不相关。 最终的代码是这样的:
<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"/>
<xslt:if test="b">
<b>
<xsl:copy-of select="b1"/>
<xsl:copy-of select="b2"/>
</b>
</xslt:if>
<xsl:copy-of select="b"/>
<xsl:copy-of select="c"/>
</xsl:copy>
</xsl:template>
答案 0 :(得分:1)
使用xsl:sort
。
以下代码不在我的头顶,可能无效;但背后的想法应该是清楚的。
<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>
答案 1 :(得分:1)
我尝试使用另一个xsl:template for“grandParent / parent / b”,但没有帮助。
由于您拥有身份模板,因此应使用<xsl:apply-templates>
代替<xsl:copy-of>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="grandParent/parent">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="a"/>
<xsl:apply-templates select="b"/>
<xsl:apply-templates select="c"/>
</xsl:copy>
</xsl:template>
现在,您可以为b
元素
<xsl:template match="parent/b">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="b1"/>
<xsl:apply-templates select="b2"/>
</xsl:copy>
</xsl:template>
这将很好地处理b
不存在的情况 - 如果select="b"
找不到任何元素,则不会触发任何模板。
实际上,如果两种情况下的排序顺序相同(按字母顺序按元素名称),那么您可以将两个模板合并为一个使用<xsl:sort>
的模板,从而完全转换
<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中的任何一个,或者您将来添加任何内容。)
答案 2 :(得分:1)
这是一个最通用的解决方案 - 使用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>
在提供的XML文档上应用此转换时:
<grandParent>
<parent>
<c>789</c>
<b>
<b2>123</b2>
<b1>456</b1>
</b>
<a>123</a>
</parent>
....
</grandParent>
产生了想要的正确结果:
<grandParent>
<parent>
<a>123</a>
<b>
<b1>456</b1>
<b2>123</b2>
</b>
<c>789</c>
</parent>
....
</grandParent>
现在,让我们更改XML文档中的所有名称 - 请注意,其他任何答案都不适用于此:
<someGrandParent>
<someParent>
<z>789</z>
<y>
<y2>123</y2>
<y1>456</y1>
</y>
<x>123</x>
</someParent>
....
</someGrandParent>
我们应用相同的转换,它会再次生成正确的结果:
<someGrandParent>
<someParent>
<x>123</x>
<y>
<y1>456</y1>
<y2>123</y2>
</y>
<z>789</z>
</someParent>
....
</someGrandParent>