使用XSLT 1.0移除无指定属性子节点的node元素
问题:使用XSLT 1.0移除不包含指定属性子节点的
node元素 需求
移除所有**不包含带有value、left-value或right-value属性的子节点(含后代节点)**的node元素。
初始XML
<?xml version="1.0" encoding="UTF-8"?> <node> <left-node key="Network0"> <node key="@FR" value="tom"/> </left-node> <node key="Network1"> <node key="PortNumber" left-value="12000" right-value="12001"/> <node key="Location"/> </node> <node key="Network2"> <node key="PortNumber" left-value="12000" right-value="12001"/> <node key="Location"> <node key="Office" left-value="IT" right-value="HR"/> <right-node key="GO" value="Yellow"/> </node> <right-node key="Try"/> </node> <node key="Network3"> <node key="Location"> <node key="Hardware"/> <node key="Software"/> </node> </node> <right-node key="Network4"> <node key="@GB" value="tim"/> </right-node> </node>
期望输出XML
<?xml version="1.0" encoding="UTF-8"?> <node> <left-node key="Network0"> <node key="@FR" value="tom"/> </left-node> <node key="Network1"> <node key="PortNumber" left-value="12000" right-value="12001"/> </node> <node key="Network2"> <node key="PortNumber" left-value="12000" right-value="12001"/> <node key="Location"> <node key="Office" left-value="IT" right-value="HR"/> <right-node key="GO" value="Yellow"/> </node> <right-node key="Try"/> </node> <right-node key="Network4"> <node key="@GB" value="tim"/> </right-node> </node>
当前有问题的XSLT实现
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <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> <xsl:template match="node[not(@value!='' or @right-value!='' or @left-value!='') ]"/> </xsl:stylesheet>
问题分析与修正
当前代码的问题在于:仅检查了node元素自身是否带有value/left-value/right-value属性,未考虑该节点的子节点或后代节点是否包含这些属性,不符合需求。
修正后的XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <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> <!-- 移除所有不包含指定属性子节点/后代节点的node元素 --> <xsl:template match="node[not(descendant::*[@value or @left-value or @right-value])]"/> </xsl:stylesheet>
修正说明
- 调整了匹配条件:
node[not(descendant::*[@value or @left-value or @right-value])]descendant::*表示匹配当前node的所有后代节点(任意层级)[@value or @left-value or @right-value]筛选出带有三个目标属性中任意一个的后代节点not(...)表示当不存在这类后代节点时,匹配该node并将其移除(空模板不输出内容)
内容的提问来源于stack exchange,提问作者user21328647
相关产品推荐
相关产品推荐

