xsl:for-each 是 XSLT 中基于 XPath“拉取”节点的直接循环工具,每次切换当前上下文,支持 position() 序号、mod 奇偶判断、sort 排序、position()≤N 限定数量,XSLT 1.0 需 key+generate-id() 去重,2.0+ 支持 for-each-group 分组。

xsl:for-each 是 XSLT 里最常用、最直接的循环工具,它不依赖模板匹配,而是用 XPath 表达式“拉取”节点,然后对每个节点依次处理。用法简单,但细节决定效果——比如上下文切换、位置控制、去重或排序,稍不注意就容易出错。
基础写法:选中节点并逐个处理
核心就一句:。select 是必需属性,必须写一个合法的 XPath,指向你要遍历的一组节点。
- 每次进入循环,当前节点(
.)自动切换为被选中的那个节点,所有相对路径(如title、artist)都基于它解析 - 循环体内部可以嵌套任意 XSLT 指令:value-of、if、sort、attribute 等
- 常见错误是 select 写成绝对路径却忽略根结构,比如 XML 根是
,那就得写catalog/cd,不能只写cd
加序号、奇偶行、倒序这些实用技巧
不用额外变量,靠内置函数就能搞定常见排版需求。
- 显示序号:用
position(),从 1 开始计数,例如 - 奇偶行变色:结合
position() mod 2判断,值为 1 是奇数行,0 是偶数行 - 倒序排列:在 for-each 内部加
- 只取前 N 条:把条件写进 select,比如
book[position()
去重和分组:XSLT 1.0 和 2.0 差别很大
原生 for-each 不自带去重,得靠组合技巧;XSLT 2.0+ 提供了更简洁的方案。
- XSLT 1.0 去重:定义
+generate-id()配合使用,语法略绕但稳定可靠 - XSLT 2.0+ 分组:直接用
,再用current-grouping-key()和current-group()拿数据 - 注意:group-by 的值必须是字符串类型,数值或日期需用 string() 或 format-date() 转一下
小心上下文丢失和嵌套陷阱
for-each 会改变当前上下文,但不会影响外层模板的上下文。嵌套时容易搞混“谁是谁的子节点”。
- 在循环内想访问父级数据(比如总记录数),要用
count(/catalog/cd)这类绝对路径,而不是count(cd) - 嵌套 for-each 时,内层的
position()是相对于内层节点集的,不是全局序号 - 避免在 for-each 里反复写相同逻辑,可抽成
提高可读性
基本上就这些。写 for-each 不复杂,但容易忽略上下文和 XPath 范围,多调试几次 select 表达式,基本就稳了。










