使用MSXML6+XSLT过滤XML节点时,如何保留自闭合标签格式
如何让XSLT处理后保留XML自闭合标签
问题背景
有这样一段初始XML:
<osmChange> <way id="304298875"> <nd ref="3088293757"/> <tag k="name" v="Tizard Place"/> </way> <way id="305295788"> <nd ref="12232709336"/> <nd ref="3099014747"/> <tag k="building" v="train_station"/> </way> </osmChange>
用MSXML6的transformNode命令执行下面的XSLT,目的是过滤掉所有<nd>节点:
<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="nd"/>
结果确实过滤掉了<nd>,但剩下的<tag>节点被改成了非自闭合的格式:
<way id="305295788"> <tag k="building" v="train_station"> </tag> </way>
需要修改XSLT,让<tag>保持<tag k="..." v="..."/>这种自闭合的形式。
可行解决方案
方案1:修改XSLT,添加输出配置并显式处理空元素
在XSLT开头加上输出声明,同时给空元素(没有子节点的元素)单独写模板,强制输出自闭合标签:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 配置XML输出格式 --> <xsl:output method="xml" omit-xml-declaration="yes" indent="yes" /> <!-- 基础的复制模板 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 过滤nd节点 --> <xsl:template match="nd"/> <!-- 针对没有子节点的元素,输出自闭合标签 --> <xsl:template match="*[not(node())]"> <xsl:copy> <xsl:apply-templates select="@*"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
这个方案通过专门匹配空元素的模板,告诉XSLT处理器:只要元素没有子节点,就输出成自闭合的形式,而不是展开成开始+结束标签。
方案2:改用transformNodeToObject配合XMLWriter控制输出
如果方案1效果不理想,可以换用MSXML的transformNodeToObject方法,结合XMLWriter来精确控制输出格式:
- 先创建XMLWriter并设置参数:
Set xmlWriter = CreateObject("MSXML2.MXXMLWriter.6.0") xmlWriter.indent = True ' 保持缩进格式 xmlWriter.omitXMLDeclaration = True ' 不需要XML声明 xmlWriter.output = Response ' 这里可以替换成你需要的输出目标,比如文件流
- 创建SAX处理器并关联XMLWriter,再执行转换:
Set saxReader = CreateObject("MSXML2.SAXXMLReader.6.0") saxReader.contentHandler = xmlWriter ' 替换成你的XML文档和XSLT文档对象 saxReader.parse(xmlDoc.transformNodeToObject(xsltDoc, xmlWriter))
XMLWriter可以强制空元素以自闭合标签的形式输出,避免transformNode默认的序列化行为。
内容的提问来源于stack exchange,提问作者DaveF
相关产品推荐
相关产品推荐

