如何通过XSLT移除包含空属性的XML节点?
问题分析
你当前的XSLT模板只是过滤掉了空值属性,但并没有对节点本身做判断——即使节点的所有属性都被移除了,模板依然会复制这个空节点(比如<id/>)。这就是为什么<id>节点还被保留的核心原因。
解决方案
我们需要补充逻辑:当一个元素节点在移除所有空属性后,既没有剩余属性,也没有任何子节点(文本、嵌套元素等)时,就完全跳过这个节点,不进行复制输出。修改后的XSLT代码如下:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- 基础复制模板:保留非空属性和所有有效子节点 --> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="@*[.!='']" /> <xsl:apply-templates select="node()" /> </xsl:copy> </xsl:template> <!-- 新增过滤模板:匹配无属性且无子节点的空元素,直接跳过 --> <xsl:template match="*[not(@*[.!='']) and not(node())]" /> </xsl:stylesheet>
代码说明
- 原有的基础模板继续保留,负责复制节点、过滤空属性并处理子节点;
- 新增的模板专门针对空元素节点:
*匹配所有元素类型;not(@*[.!=''])检查该元素是否没有任何非空属性;and not(node())检查该元素是否没有任何子节点(包括文本、嵌套元素等);- 这个模板没有输出内容,意味着匹配到的这类节点会被直接移除,不会出现在最终结果里。
测试验证
输入XML:
<Test><id value=""></id><name value="Test"></name></Test>
输出XML:
<Test><name value="Test" /></Test>
完全符合你的期望输出。另外如果遇到类似<id value="">123</id>的节点(空属性但有非空文本),这个逻辑也会保留节点并输出<id>123</id>,兼顾了其他场景的合理性。
内容的提问来源于stack exchange,提问作者nkn
相关产品推荐
相关产品推荐

