为什么以前的代码输出 TEXT,我为什么要坚持 XSL 忽略所有其他文本?是所有 XML 解析器的行为还是我自己的行为
您正在发现规范中指定的最基本的 XSLT 特性之一:XSLT 的内置模板。
从规格:
有一个内置的模板规则允许递归处理在样式表中的显式模板规则没有成功模式匹配的情况下继续进行。此模板规则适用于元素节点和根节点。下面显示了内置模板规则的等效项:
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
每种模式还有一个内置的模板规则,它允许递归处理在样式表中的显式模板规则没有成功匹配模式的情况下以相同的模式继续。此模板规则适用于元素节点和根节点。下面显示了模式 m 的内置模板规则的等效项。
<xsl:template match="*|/" mode="m">
<xsl:apply-templates mode="m"/>
</xsl:template>
还有一个用于复制文本的文本和属性节点的内置模板规则:
<xsl:template match="text()|@*">
<xsl:value-of select="."/>
</xsl:template>
处理指令和注释的内置模板规则是什么都不做。
<xsl:template match="processing-instruction()|comment()"/>
命名空间节点的内置模板规则也是什么都不做。没有可以匹配命名空间节点的模式;因此,内置模板规则是唯一适用于命名空间节点的模板规则。
内置模板规则被视为在样式表之前隐式导入,因此其导入优先级低于所有其他模板规则。因此,作者可以通过包含显式模板规则来覆盖内置模板规则。
因此,报告的行为是应用内置模板的结果——这三个模板中的第一个和第二个。
用您自己的模板覆盖内置模板是一种很好的 XSLT 设计模式,每当调用时都会发出错误消息,以便程序员立即知道他的转换正在“泄漏”:
例如,如果有这个 XML 文档:
<a>
<b>
<c>Don't want to see this</c>
</b>
</a>
并使用此转换进行处理:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="a|b">
<xsl:copy>
<xsl:attribute name="name">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
结果是:
<a name="a">
<b name="b">Don't want to see this</b>
</a>
并且程序员会非常困惑不需要的文本是如何出现的。
但是,仅添加它catch-all template
有助于避免任何此类混淆并立即捕获错误:
<xsl:template match="*">
<xsl:message terminate="no">
WARNING: Unmatched element: <xsl:value-of select="name()"/>
</xsl:message>
<xsl:apply-templates/>
</xsl:template>
现在,除了令人困惑的输出之外,程序员还会收到一个警告,立即解释问题:
WARNING: Unmatched element: c
Michael Kay 后来为 XSLT 3.0 添加的内容
xsl:mode
在 XSLT 3.0 中,您可以在声明中指定回退行为,而不是添加包罗万象的模板规则。例如,<xsl:mode on-no-match="shallow-skip"/>
导致所有不匹配的节点(包括文本节点)被跳过,而<xsl:mode on-no-match="fail"/>
将不匹配视为错误,并<xsl:mode warning-on-no-match="true"/>
导致警告。