在XSLT的转换流程中,模板匹配由match属性决定,而mode属性则负责把匹配结果进一步分流。对于同一个源节点,不同mode可以绑定不同的模板规则,让处理器按照调用方指定的模式输出完全不同的结构。例如章节节点既可以被渲染成完整正文,也可以仅提取标题生成目录,这种能力能够在不改动XML结构的前提下实现多视图输出。

mode的基本概念与匹配规则
模式是 <xsl:template> 元素和 <xsl:apply-templates> 元素上的一个可选属性。它相当于给模板打上命名标记,只有带相同mode的调用才能触发该模板。没有指定mode的模板属于默认模式,只有不带mode的调用才会匹配它们。换句话说,mode把模板库划分成了多个相互隔离的命名空间,不同mode下的规则彼此不会串扰。
例如下面的样式表中针对同一个chapter节点声明了两套模板。第一套带有 mode="toc",负责输出列表项;第二套没有mode,负责输出完整章节内容。两者虽然匹配同一个节点,却分别在不同的调用路径下生效。
<?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" encoding="UTF-8"/>
<xsl:template match="chapter" mode="toc">
<li><xsl:value-of select="title"/></li>
</xsl:template>
<xsl:template match="chapter">
<section>
<h2><xsl:value-of select="title"/></h2>
<p><xsl:value-of select="para"/></p>
</section>
</xsl:template>
</xsl:stylesheet>
处理器在选择模板时,会先根据 <xsl:apply-templates> 的select表达式选取节点,再比较mode标记。如果调用没有写mode,那么带mode的模板不会参与匹配;如果调用写的是 mode="toc",那么默认模式下的模板也不会被选中。这种隔离机制避免了同一组节点在多路输出时发生模板覆盖或冲突。
如何对同一节点应用不同模板
要理解mode的核心价值,最好的方式是一次转换中对同一批节点执行两次不同模式的调用。下面这段样式表输入一个商品目录,同一组item节点先被 mode="list" 处理成列表项,随后又被 mode="detail" 处理成带价格信息的详情块。源XML如下。
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<item sku="1001">
<name>机械键盘</name>
<price>399</price>
</item>
<item sku="1002">
<name>无线鼠标</name>
<price>159</price>
</item>
</catalog>
对应的XSLT样式表如下。根模板中第一次调用 <xsl:apply-templates select="catalog/item" mode="list"/>,只触发 list 模式下的item模板;第二次调用 <xsl:apply-templates select="catalog/item" mode="detail"/>,则触发 detail 模式下的item模板。两次选择的节点完全相同,但输出结构完全不同。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:template match="/">
<html>
<body>
<ul>
<xsl:apply-templates select="catalog/item" mode="list"/>
</ul>
<hr/>
<xsl:apply-templates select="catalog/item" mode="detail"/>
</body>
</html>
</xsl:template>
<xsl:template match="item" mode="list">
<li><xsl:value-of select="name"/></li>
</xsl:template>
<xsl:template match="item" mode="detail">
<div>
<h3><xsl:value-of select="name"/></h3>
<span><xsl:value-of select="price"/></span>
</div>
</xsl:template>
</xsl:stylesheet>
如果没有mode,两个同时匹配item节点的模板会形成冲突,XSLT 1.0处理器通常会报错,因为同一节点匹配到多个具有相同默认优先级的模板。而引入mode之后,两个模板分别属于 list 和 detail 两个模式,它们之间不再直接竞争。这样就能安全地保留多种处理逻辑。
需要注意的是,<xsl:apply-templates> 上的mode必须与 <xsl:template> 上的mode严格对应。如果调用指定了 mode="list",但样式表中没有任何模板声明该mode,处理器不会退回使用无mode模板,而是按照该模式下的内置规则继续处理子节点。这种静默行为有时会让输出明显缺失,因此调试多模式样式表时,应当逐个确认调用与模板声明是否成对出现。
命名模式的实际应用场景
mode并不是只用于演示的小工具,它在实际项目中的价值非常突出。一个典型的场景是文档发布系统:源XML中包含大量章节和段落,网站既需要生成完整正文,又需要生成站内目录。目录通常只需要章节标题,而正文需要标题、段落、图片、列表等全部内容。使用 mode="toc"
XSLTmodeapply-templates修改时间:2026-08-13 02:59:09