UPDATE(剧透):这个问题得到了解答(请参阅下面的David Carlisle回答),它看起来像是JRE中某些版本中包含的XSLT实现中的错误(就像它在jdk中工作但在jre 1.6.0_20上不起作用) -b02并且在1.6.0_31-b05完全没有工作。我在Oracle网站上记录了一个bug。
我几乎就在那里,在功能方面它现在有效。但是我对它的某些部分不满意,其中一些(我相信)可能会更短。这是一个问题......详见下文
这是输入xml
的示例<?xml version="1.0" encoding="UTF-8"?>
<t1>
<t2 a1="v1">
<ot1 a2="v2" />
<ot2 a3="v3">
<t3 a5="v4">
<ot1 a2="v5" />
</t3>
</ot2>
</t2>
</t1>
这是预期结果xml的一个示例(请参阅下面的xslt文件,了解最新信息 -
<?xml version="1.0" encoding="UTF-8"?>
<t1>
<t2 a1="v1">
<gt2 a="ot2" b="gtv1">
<gt1 a="ot1">v2</gt1>
</gt2>
<gt2 a="ot2" b="v3">
<t3 a5="v4">
<gt2 a="ot2" b="gtv1">
<gt1 a="ot1">v5</gt1>
</gt2>
</t3>
</gt2>
</t2>
</t1>
这是xslt我终于结束了(但不太高兴)。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common" version="1.0"
exclude-result-prefixes="exslt">
<xsl:output method="xml" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="ot1|ot2">
<xsl:variable name="thisResult">
<xsl:apply-templates select="." mode="impl" />
</xsl:variable>
<xsl:apply-templates select="exslt:node-set($thisResult)" />
</xsl:template>
<xsl:template match="ot1" mode="impl">
<ot2 a3="gtv1">
<gt1 a="ot1">
<xsl:value-of select="@a2" />
</gt1>
</ot2>
</xsl:template>
<xsl:template match="ot2" mode="impl">
<gt2 a="ot2" b="{@a3}">
<xsl:for-each select="child::*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*|node()" />
</xsl:element>
</xsl:for-each>
</gt2>
</xsl:template>
</xsl:stylesheet>
问题是:如何缩短它?
<xsl:for-each select="child::*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*|node()" />
</xsl:element>
</xsl:for-each>
我尝试了以下内容,但在这种情况下,生成的xml的一部分将丢失(特别是gt2元素的属性将丢失)
<xsl:copy-of select="node()"/>
也尝试了
<xsl:copy-of select="*"/>
没有成功
答案 0 :(得分:3)
我需要定义能够执行所谓的xslt转换 “多次转型”。
此处无需使用多次传递处理。
这个简短而简单的转型:
<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="ot1">
<gt1 a="ot1"><xsl:value-of select="@a2"/></gt1>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="ot2">
<gt2 a="ot2" b="{@a3}"/>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<t1>
<t2 a1="v1">
<ot1 a2="v2" />
<ot2 a3="v3">
<t3 a5="v4">
<ot1 a2="v5" />
</t3>
</ot2>
</t2>
</t1>
生成想要的正确结果:
<t1>
<t2 a1="v1">
<gt1 a="ot1">v2</gt1>
<gt2 a="ot2" b="v3"/>
<t3 a5="v4">
<gt1 a="ot1">v5</gt1>
</t3>
</t2>
</t1>
更新:在OP已经与自己认为需要多通道处理更新的问题 - 这仍然是不正确的。
。以下是新问题的简短解决方案,一次性传递:
<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="ot1">
<gt2 a="ot2" b="gtv{substring-after(name(), 'ot')}">
<gt1 a="ot1"><xsl:value-of select="@a2"/></gt1>
</gt2>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="ot2">
<gt2 a="ot2" b="{@a3}"/>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
将此转换应用于新提供的XML源文档时:
<t1>
<t2 a1="v1">
<ot1 a2="v2" />
<ot2 a3="v3">
<t3 a5="v4">
<ot1 a2="v5" />
</t3>
</ot2>
</t2>
</t1>
再次生成想要的正确结果:
<t1>
<t2 a1="v1">
<gt2 a="ot2" b="gtv1">
<gt1 a="ot1">v2</gt1>
</gt2>
<gt2 a="ot2" b="v3"/>
<t3 a5="v4">
<gt2 a="ot2" b="gtv1">
<gt1 a="ot1">v5</gt1>
</gt2>
</t3>
</t2>
</t1>
<强> UPDATE2 强>:由于OP是要求的他的当前代码重构,特别需要更好地表达此摘录:
<xsl:for-each select="child::*"> <xsl:element name="{name()}"> <xsl:copy-of select="@*|node()" /> </xsl:element> </xsl:for-each>
这是一个明显的重构 - 只需用:
替换上面的内容<xsl:apply-templates/>
完成此修改后,完整代码:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common" version="1.0"
exclude-result-prefixes="exslt">
<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="ot1|ot2">
<xsl:variable name="thisResult">
<xsl:apply-templates select="." mode="impl" />
</xsl:variable>
<xsl:apply-templates select=
"exslt:node-set($thisResult)" />
</xsl:template>
<xsl:template match="ot1" mode="impl">
<ot2 a3="gtv1">
<gt1 a="ot1">
<xsl:value-of select="@a2" />
</gt1>
</ot2>
</xsl:template>
<xsl:template match="ot2" mode="impl">
<gt2 a="ot2" b="{@a3}">
<xsl:apply-templates/>
</gt2>
</xsl:template>
</xsl:stylesheet>
并应用于最新提供的源XML文档:
<t1>
<t2 a1="v1">
<ot1 a2="v2" />
<ot2 a3="v3">
<t3 a5="v4">
<ot1 a2="v5" />
</t3>
</ot2>
</t2>
</t1>
生成了想要的结果:
<t1>
<t2 a1="v1">
<gt2 a="ot2" b="gtv1">
<gt1 a="ot1">v2</gt1>
</gt2>
<gt2 a="ot2" b="v3">
<t3 a5="v4">
<gt2 a="ot2" b="gtv1">
<gt1 a="ot1">v5</gt1>
</gt2>
</t3>
</gt2>
</t2>
</t1>
答案 1 :(得分:2)
Dimitre已经展示了另一种策略,但为了回答原始帖子中的问题,xsl:for-each(除了一些未显示在此处的命名空间效果)相当于一个
<xsl:copy-of select="*"/>
如果替换xsl:for-each,我会获得相同的输出。
您建议的替代
<xsl:copy-of select="node()"/>
几乎相同,但是拾取用于缩进源的空白节点,因此输出在空白区域不同。
你说
(特别是gt3元素的属性将丢失)
但编码更改不会更改属性,示例输入或输出中没有gt3
元素?