如何使用XSLT 1.0移除子元素为空或不存在的XML element节点?
问题需求
需要处理XML文档,当<element>节点的field1和field2子元素**均不存在或内容为空(含空白字符)**时,移除该<element>节点。
输入示例
<root><!-- document --> <element><!-- keep --> <field1>A</field1> </element> <element><!-- keep --> <field2>B</field2> </element> <element><!-- delete --> <field1/> </element> <element><!-- delete --></element> <element/><!-- delete --> </root>
当前失效的XSLT 1.0代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <xsl:copy-of select="node()"/> </xsl:template> <xsl:template match="element"> <xsl:choose> <xsl:when test="field1 or field2"> <xsl:copy> <xsl:copy-of select="node()"/> </xsl:copy> </xsl:when> <xsl:otherwise/> </xsl:choose> </xsl:template> </xsl:stylesheet>
问题原因
根模板使用了<xsl:copy-of select="node()"/>,该指令会直接复制整个节点树,完全绕过后续针对element节点的模板匹配逻辑,导致过滤规则无法生效。
解决方案
使用XSLT的身份模板默认复制所有节点,再针对需要过滤的element节点编写匹配模板,仅保留符合条件的节点:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 身份模板:默认复制所有节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 过滤不符合条件的element节点 --> <xsl:template match="element[ (not(field1) or normalize-space(field1) = '') and (not(field2) or normalize-space(field2) = '') ]"/> </xsl:stylesheet>
规则说明
normalize-space(field1) = '':同时处理空节点(如<field1/>)、仅含空白字符的节点(如<field1> </field1>)- 当
element节点的field1和field2都满足「不存在或内容为空/空白」时,该模板匹配后不输出任何内容,即移除该节点 - 其他
element节点会通过身份模板被保留并复制
内容的提问来源于stack exchange,提问作者James Taylor
相关产品推荐
相关产品推荐

