XSLT作为把XML文档转换成其他格式的核心语言,其apply-templates指令承担着驱动模板匹配与执行的关键任务。很多转换逻辑写不对,其实是因为没搞清它选择节点的几种机制。下面我们直接拆解这些方式,并配合代码说明。
一、默认选择:处理全部子节点
当apply-templates不写select属性时,它会选中当前节点的所有子节点(包括元素、文本、注释、处理指令),然后逐一寻找匹配的模板。这种方式适合自顶向下、无差别递归输出的场景。
比如有一个图书列表XML,根节点下有多个book子元素,我们在根模板里直接写apply-templates,就能让每个book去匹配对应的模板。它的好处是结构清晰、代码量少,但如果某些节点你不想处理,就会被默认带出来,需要靠模板里的优先级或空模板屏蔽。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="book">
<p><xsl:value-of select="title"/></p>
</xsl:template>
</xsl:stylesheet>
上面这段里,根模板中的apply-templates没有select,于是把根下所有子节点交给后续模板。如果book之外还有一个info节点,而你没有写匹配info的模板,XSLT内置的默认模板就会把它文本内容直接输出,这常常让人困惑。
二、使用select属性做XPath精确选择
更常用的做法是在apply-templates上加select,其值是一个XPath表达式,只把符合条件的节点送进模板匹配流程。这样你可以控制顺序、过滤数据、跨层选取。
例如只处理价格大于30的book,或者先输出所有书名再输出作者,都靠select实现。它的优势是逻辑显式、可控性强,缺点则是XPath写错时调试稍麻烦。下面示例从books里挑出前两个book,并只取title节点做处理:
<xsl:template match="/">
<ul>
<xsl:apply-templates select="books/book[position() <= 2]/title"/>
</ul>
</xsl:template>
<xsl:template match="title">
<li><xsl:value-of select="."/></li>
</xsl:template>
这里select用了位置谓词和子节点路径,只把title元素送进匹配。注意XPath里的小于号在XML属性中要写成<,否则文件不合法。通过select,你完全掌握了节点选择的主动权。
三、用mode属性分组处理同类节点
同一个节点有时要在不同地方以不同形式输出,比如book既要在目录里列名字,又要在详情区展描述。此时给apply-templates加mode,并在模板上写相同mode,就能把匹配分组,互不干扰。
mode相当于给模板匹配开了平行通道。没有mode的模板处理默认流,带mode的只在对应apply-templates mode="..."时被启用。下面展示同一批book节点,分别用目录模式和详情模式输出:
<xsl:template match="/">
<h3>目录</h3>
<xsl:apply-templates select="books/book" mode="toc"/>
<h3>详情</h3>
<xsl:apply-templates select="books/book" mode="detail"/>
</xsl:template>
<xsl:template match="book" mode="toc">
<p><xsl:value-of select="title"/></p>
</xsl:template>
<xsl:template match="book" mode="detail">
<div>
<strong><xsl:value-of select="title"/></strong>
<span><xsl:value-of select="desc"/></span>
</div>
</xsl:template>
mode让节点选择从“选谁”扩展到“以什么身份选”,是大型样式表解耦的利器。不过mode名多了也需规范命名,避免冲突。
四、结合with-param做选择性传递
虽然with-param不直接决定选哪些节点,但常和select配合使用:先靠select圈定节点,再通过参数告诉模板该怎么处理。例如select出book后,传一个是否显示价格的参数。
这种组合让选择节点的同时附带上下文,模板内部就能分支渲染。示例如下:
<xsl:template match="/">
<xsl:apply-templates select="books/book">
<xsl:with-param name="showPrice" select="true()"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="book">
<xsl:param name="showPrice"/>
<p>
<xsl:value-of select="title"/>
<xsl:if test="$showPrice">
<em>价格:<xsl:value-of select="price"/></em>
</xsl:if>
</p>
</xsl:template>
综上,apply-templates选择节点主要有默认全选、select精确选、mode分组选三种核心方式,配合参数可进一步细化。弄清它们,XSLT转换就不再盲目。
XSLTapply-templatesxpath_selection修改时间:2026-08-01 22:18:37