xslt递归处理树形xml的核心是配合匹配子节点的模板实现自动向下递归;通过match属性定义模板、select指定子节点、mode或条件判断区分层级、with-param传递上下文,并确保select明确及strip-space防干扰。

XSLT 递归处理树形结构 XML,核心是用 <apply-templates></apply-templates> 配合匹配子节点的模板,让处理器自动“向下走”,遇到子元素就再调用自己——这本质上就是递归。
用 match 和 apply-templates 构建递归入口
树形 XML 通常有嵌套的同名元素(如 <node></node> 套 <node></node>),XSLT 不需要写 for 或 while,而是靠模板匹配驱动递归:
- 定义一个模板匹配
node元素(或任意父级容器) - 在该模板内部,用
<apply-templates select="node"></apply-templates>显式处理所有直接子node - 因为子
node也满足match="node",所以会再次进入同一模板——递归发生
控制递归深度和边界:用 mode 或条件隔离不同层级
有时根节点和叶子节点要渲染不同内容,光靠匹配不够。可用以下方式区分:
- 加
mode属性:比如<apply-templates select="node" mode="child"></apply-templates>,再写单独的match="node" mode="child"模板 - 用
<if test="not(node)"></if>判断是否为叶子节点(无子node) - 用
<if test="parent::node"></if>判断是否非根(有父级node)
传递上下文信息:用 <with-param></with-param> 带深度或路径
纯模板递归不带参数,但常需知道当前层级、祖先路径或编号。这时要用命名模板 + <call-template></call-template> 主动递归:
- 把逻辑封装进
<template name="render-node"></template> - 首次调用时传入初始参数:
<xsl:call-template name="render-node"><xsl:with-param name="depth" select="1"/></xsl:call-template></li> <li>模板内处理完本层后,对每个子节点再次 <code><xsl:call-template>
,并传入$depth + 1
避免无限递归:确保有明确终止条件
XSLT 不会栈溢出,但若模板总匹配自己又没限制子集,可能重复处理或漏数据:
- 始终用
select="xxx"明确指定下一层要处理的子节点(如select="child::node"),别用select="*"意外匹配到文本/注释 - 如果 XML 有混合内容(文本+元素),加
<strip-space elements="*"></strip-space>清除空白文本节点干扰 - 用
<template match="text()"></template>空模板忽略无关文本,防止默认规则介入
基本上就这些。XSLT 的递归不是编程语言里的函数调用,而是声明式“匹配→应用→再匹配”的自然展开。写熟了,比手写 for 循环还干净。










