XSLT 模板与匹配
本章定位 :掌握 XSLT 模板(
xsl:template)的定义和匹配机制——match 模式语法、xsl:apply-templates递归处理、模板优先级规则。
定义与作用
XSLT 的核心是模板(Template)。一个 XSLT 样式表就是一组模板规则,每个模板声明"当遇到特定节点时,按什么规则转换"。
模板通过 match 属性(XPath 模式)指定触发条件。XSLT 处理器遍历源树,对每个节点寻找最佳的匹配模板并执行。
关键机制是 xsl:apply-templates——它不直接输出,而是说"我不处理子节点了,交给它们的模板去处理"。这种递归传递机制赋予 XSLT 强大的灵活性:你只需为感兴趣的节点写模板,其余的自动跳过或走默认规则。
核心原理:模板匹配与冲突解决
图解释 :当多个模板匹配同一节点时,XSLT 处理器按优先级选择——更具体的模式优先级更高。内置优先级规则:属性/元素名 > 通配符;带谓词 > 不带谓词。
语法/结构要点
match 模式类型
| 模式 | 匹配 | 优先级 |
|---|---|---|
/ | 文档根 | 0.5 |
book | 名为 book 的元素 | 0 |
* | 任意元素 | -0.5 |
book[@category] | 带 category 属性的 book | 0.5 |
book[@category='web'] | category=web 的 book | 0.5 |
@* | 任意属性 | -0.5 |
text() | 文本节点 | -0.5 |
| `book | cd` | book 或 cd |
内置默认模板(隐含)
XSLT 内置了几个默认模板,即使你不写也会生效:
<!-- 默认1:递归处理元素子节点 -->
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
<!-- 默认2:输出文本节点内容 -->
<xsl:template match="text()|@*">
<xsl:value-of select="."/>
</xsl:template>
如果你为某个元素写了模板,默认模板对该元素失效——你的模板接管处理权。
完整示例:大翔用模板实现条件渲染
场景说明
飞翔科技的运维 大翔 要生成服务器状态报告。有些服务器在线、有些离线,他需要根据状态用不同颜色渲染。
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="html"/>
<!-- 根模板 -->
<xsl:template match="/">
<html><body>
<h2>飞翔科技服务器状态</h2>
<table border="1">
<tr><th>服务器</th><th>IP</th><th>状态</th></tr>
<xsl:apply-templates select="servers/server"/>
</table>
</body></html>
</xsl:template>
<!-- 在线服务器:绿色 -->
<xsl:template match="server[@status='online']">
<tr style="background-color:#d4edda;">
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="ip"/></td>
<td>在线 ✓</td>
</tr>
</xsl:template>
<!-- 离线服务器:红色 -->
<xsl:template match="server[@status='offline']">
<tr style="background-color:#f8d7da;">
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="ip"/></td>
<td>离线 ✗</td>
</tr>
</xsl:template>
</xsl:stylesheet>
操作结果
源 XML:
<servers>
<server status="online"><name>Web01</name><ip>192.168.1.10</ip></server>
<server status="offline"><name>DB01</name><ip>192.168.1.20</ip></server>
<server status="online"><name>Web02</name><ip>192.168.1.11</ip></server>
</servers>
生成的 HTML 中,Web01/Web02 背景绿色,DB01 背景红色。XSLT 通过两个模板实现了基于属性的条件渲染——不需要任何 if-else 判断。
易错场景
错误一:覆盖了默认模板但没有显式处理子孙
<xsl:template match="bookstore">
<div><xsl:value-of select="book/title"/></div>
<!-- ❌ 只输出了第一个 title,其他 book 丢失 -->
</xsl:template>
写了模板后,该节点的子节点不会走默认模板。需要 xsl:apply-templates 传递。
错误二:match="book" 同时匹配了多个 book
<xsl:template match="book">
<!-- 这个模板会为每个 book 执行一次 -->
<p><xsl:value-of select="title"/></p>
</xsl:template>
XSLT 自动为每个匹配的节点执行一次模板——不用写循环。
面试考点
| 考点 | 参考答案要点 |
|---|---|
| XSLT 模板的冲突解决规则是什么? | 多个模板匹配同一节点时,取优先级最高的。具体模式(如 book)优先于通配符(*),带谓词的模式优先级更高 |
| xsl:apply-templates 的作用? | 将处理权传递给 select 指定的子节点(或当前节点的所有子节点),由对应的模板继续处理。这是 XSLT 递归处理的核心 |
| 内置默认模板的作用? | 即使不写任何模板,XSLT 也会递归遍历所有节点并输出文本内容。写了模板后,对应元素不再走默认模板 |