XSLT转换XML时,为何docTrans节点文本被额外输出?
XSLT转换时意外输出docTrans节点内容的原因及解决方法
问题场景
我需要用XSLT将一份XML转换为另一份XML,相关代码和输出如下:
输入XML
<?xml version='1.0' encoding='UTF-8'?> <message> <bo> <root> <payee>TMCH500000</payee> </root> </bo> <docTrans> <number>90001640</number> <docType>SETTLEMENT</docType> <createdOn>2023-04-12T10:21:31.231</createdOn> </docTrans> </message>
使用的XSLT
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="no"/> <xsl:template match="/message/bo/root"> <node><xsl:value-of select="payee" /></node> </xsl:template> </xsl:stylesheet>
实际输出
<node>TMCH500000</node> 90001640 SETTLEMENT 2023-04-12T10:21:31.231
期望输出
<?xml version='1.0' encoding='UTF-8'?> <node>TMCH500000</node>
疑问
docTrans节点下的所有文本也被输出了,原因是什么?
原因分析
XSLT存在内置模板规则(默认模板),当未为某个节点编写匹配模板时,处理器会自动套用这些规则:
- 对元素节点:内置模板会递归处理其所有子节点
- 对文本节点:内置模板会直接输出文本内容
你编写的XSLT仅匹配了/message/bo/root节点,但未处理message、docTrans及其子节点,所以处理器会对这些未匹配节点应用内置模板:
- 从根节点开始,找不到
message的匹配模板,于是处理它的子节点bo和docTrans - 处理
bo时,同样无匹配模板,继续处理其子节点root,此时命中你编写的模板,输出<node>TMCH500000</node> - 处理
docTrans时,无匹配模板,递归处理其下的number、docType、createdOn节点;这些元素节点也无匹配模板,最终处理它们的文本子节点,导致多余内容被输出
解决方法
要阻止多余内容输出,只需覆盖内置模板,添加一个匹配所有节点但不输出内容的模板即可:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="no"/> <!-- 匹配所有节点和属性,不输出任何内容,覆盖内置模板 --> <xsl:template match="*|@*"/> <xsl:template match="/message/bo/root"> <node><xsl:value-of select="payee" /></node> </xsl:template> </xsl:stylesheet>
或者直接匹配根节点/,仅处理需要的部分:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="no"/> <xsl:template match="/"> <node><xsl:value-of select="/message/bo/root/payee" /></node> </xsl:template> </xsl:stylesheet>
两种方式都能得到期望输出,同时避免多余内容被输出。
内容的提问来源于stack exchange,提问作者Joseph Cen
相关产品推荐
相关产品推荐

