我正在尝试从XML文件中删除节点。我只需要为每个XML使用一个XSLT,我需要根据文档元素的子项数在XSLT中做出决策。
<root>
<branch>
<foo>bar</foo>
</branch>
<root>
应该变成
<branch>
</branch>
但是
<root>
<branch>
<foo>bar</foo>
</branch>
<branch>
<foo>baz</foo>
<root>
到
<root>
<branch>
</branch>
<branch>
</branch>
<root>
也就是说,如果根元素的(仅)子元素在应用XSLT后可以充当结果XML的新文档根,则应该删除它。每次出现时都必须删除<foo>
个节点。
有没有办法用单个XSL执行此操作?
答案 0 :(得分:2)
尝试
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root[*[2]]">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="root[* and not(*[2])]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="branch/foo"/>
答案 1 :(得分:2)
更简单,更短,更通用(没有元素名称硬编码)解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*[not(*[2])]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="/*/*/node()"/>
</xsl:stylesheet>
将此转换应用于第一个提供的XML文档(更正为格式良好):
<root>
<branch>
<foo>bar</foo>
</branch>
</root>
产生了想要的正确结果:
<branch></branch>
对第二个提供的XML文档应用相同的转换(再次需要针对格式良好进行更正):
<root>
<branch>
<foo>bar</foo>
</branch>
<branch>
<foo>baz</foo>
</branch>
</root>
再次生成想要的正确输出:
<root>
<branch></branch>
<branch></branch>
</root>
<强>解释强>:
identity rule “按原样”复制每个节点。
有两个模板覆盖特定节点的身份模板,并以不同方式处理这些节点。
第一个覆盖模板匹配没有第二个元素子元素的顶部元素。它不会复制元素本身,而是处理其子元素。
第二个覆盖模板匹配顶级元素的子元素。此模板没有正文,这意味着所有此类匹配的元素都会被忽略,并且不会包含在输出中(换句话说 - “已删除”)
请注意:
此转换可应用于任何 XML文档,无论其中的元素名称如何,仍然可以生成所需的正确结果。
例如,在应用于此XML文档时:
<t>
<b>
<f>brrr</f>
</b>
<b>
<f>bzzz</f>
</b>
</t>
产生了想要的正确结果:
<t>
<b></b>
<b></b>
</t>
将此与当前接受的答案产生的结果进行对比:
<t>
<b>
<f>brrr</f>
</b>
<b>
<f>bzzz</f>
</b>
</t>