如何修改XSLT模板匹配规则移除指定节点的空元素及空父节点
解决指定XML节点的空元素移除问题
需求说明
仅针对section[@desc='a']、section[@desc='b']、remove这三类节点执行以下处理:
- 移除节点内所有空元素(包含嵌套层级里的空元素)
- 若处理后该父节点无任何有效子元素,则连同父节点一起移除
示例XML
<?xml version="1.0" encoding="UTF-8"?> <item> <perm desc="item_1"> <section desc="a"> <delete></delete> <nondelete>a</nondelete> </section> <section desc="b"> <delete></delete> <nondelete>a</nondelete> </section> <section desc="c"> <delete></delete> <nondelete>a</nondelete> </section> <details> <firstname desc="Name">John</firstname> <lastname desc="Last"></lastname> <phone desc="phone"></phone> </details> </perm> <remove> <delete></delete> </remove> </item>
原XSLT(存在问题)
原实现会残留空父节点,且无法处理嵌套子元素里的空元素:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="section[@desc='a']|section[@desc='b']|remove/*[not(self::perm)][not(descendant::text()[normalize-space()])]" /> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
预期输出XML
<?xml version="1.0" encoding="UTF-8"?> <item> <perm desc="item_1"> <section desc="a"> <nondelete>a</nondelete> </section> <section desc="b"> <nondelete>a</nondelete> </section> <section desc="c"> <delete></delete> <nondelete>a</nondelete> </section> <details> <firstname desc="Name">John</firstname> <lastname desc="Last"/> <phone desc="phone"/> </details> </perm> </item>
修正后的XSLT方案
以下实现可处理嵌套空元素,并在父节点无有效子元素时移除父节点:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <!-- 基础复制模板:默认复制所有节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 处理目标节点:section[@desc='a']、section[@desc='b']、remove --> <xsl:template match="section[@desc='a']|section[@desc='b']|remove"> <!-- 先处理所有子节点,过滤空元素 --> <xsl:variable name="filtered-children"> <xsl:apply-templates select="node()"/> </xsl:variable> <!-- 仅当处理后有有效内容时,才复制当前节点 --> <xsl:if test="normalize-space($filtered-children) != ''"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:copy-of select="$filtered-children"/> </xsl:copy> </xsl:if> </xsl:template> <!-- 移除所有空元素(适用于目标节点的嵌套子元素) --> <xsl:template match="*[not(@*) and not(normalize-space()) and not(node())]"/> </xsl:stylesheet>
嵌套节点测试示例
对于如下嵌套结构:
<section desc="b"> <child> <a>12</a> <b></b> </child> <delete></delete> <nondelete>a</nondelete> </section>
修正后的XSLT会输出:
<section desc="b"> <child> <a>12</a> </child> <nondelete>a</nondelete> </section>
内容的提问来源于stack exchange,提问作者Somebody
相关产品推荐
相关产品推荐

