XSLT <xsl:for-each> 元素最全详解(2025 年真实用法 + 避坑指南)
<xsl:for-each> 是 XSLT 中最直观的循环指令,很多人入门第一天就用它,但老手几乎不用它(后面告诉你为什么)。
一、基本语法(就这一种写法)
<xsl:for-each select="XPath表达式">
<!-- 这里面可以写任何 XSLT 指令,会对 select 选中的每一个节点执行一次 -->
</xsl:for-each>
二、核心属性速查(记住这 3 个就够了)
| 属性 | 说明 | 常见用法 |
|---|---|---|
select | 必须,要循环的节点集合 | select="book"、select="//item[@price>50]" |
group-by(XSLT 2.0+) | 分组循环(超级好用) | 后面专门讲 |
group-adjacent | 相邻分组 |
三、10 个最常见实战用法(直接复制可用)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- 1. 最基础:遍历所有 book -->
<xsl:for-each select="library/book">
<p><xsl:value-of select="title"/></p>
</xsl:for-each>
<!-- 2. 加上序号(position() 是当前循环次数,从 1 开始) -->
<xsl:for-each select="book">
<tr>
<td><xsl:value-of select="position()"/></td>
<td><xsl:value-of select="title"/></td>
</tr>
</xsl:for-each>
<!-- 3. 倒序排列 -->
<xsl:for-each select="book">
<xsl:sort select="price" order="descending" data-type="number"/>
<xsl:value-of select="title"/>(¥<xsl:value-of select="price"/>)<br/>
</xsl:for-each>
<!-- 4. 只取前 5 本(XSLT 2.0+ 超简单) -->
<xsl:for-each select="book[position() <= 5]">
...
</xsl:for-each>
<!-- 5. 奇偶行不同颜色(经典表格技巧) -->
<xsl:for-each select="book">
<tr>
<xsl:if test="position() mod 2 = 1">
<xsl:attribute name="bgcolor">#f0f0f0</xsl:attribute>
</xsl:if>
<td><xsl:value-of select="title"/></td>
</tr>
</xsl:for-each>
<!-- 6. 生成 CSV 一行(最常用!) -->
<xsl:for-each select="book">
"<xsl:value-of select="title"/>","<xsl:value-of select="author"/>",<xsl:value-of select="price"/>
<xsl:if test="position() != last()"> </xsl:if>
</xsl:for-each>
<!-- 7. XSLT 2.0+ 分组(神技!替代老式 Muenchian 分组) -->
<xsl:for-each-group select="book" group-by="author">
<h2><xsl:value-of select="current-grouping-key()"/></h2>
<ul>
<xsl:for-each select="current-group()">
<li><xsl:value-of select="title"/></li>
</xsl:for-each>
</ul>
</xsl:for-each-group>
</xsl:for-each>
四、<xsl:for-each> vs <xsl:apply-templates>(终极对比)
| 项目 | <xsl:for-each> | <xsl:apply-templates>(推荐) |
|---|---|---|
| 可读性 | 一般(过程式) | 优秀(声明式、模板化) |
| 复用性 | 差(代码重复) | 高(一个模板到处用) |
| 性能 | 略快 | 基本持平(现代处理器优化后) |
| 是否符合 XSLT 哲学 | 不符合(命令式) | 完全符合(规则驱动) |
| 老手使用频率 | 10% | 90% |
结论(2025 年真实建议):
能用模板解决的,永远不要用 <xsl:for-each>
只在下面 3 种场景才用 <xsl:for-each>:
- 生成 CSV、JSON 这种纯顺序输出
- 临时调试
- 必须用
for-each-group分组(XSLT 2.0+)
五、XSLT 2.0+ 必学的 <xsl:for-each-group>(降维打击)
<!-- 按作者分组(最常见) -->
<xsl:for-each-group select="book" group-by="author">
<xsl:value-of select="current-grouping-key()"/> 共写了
<xsl:value-of select="count(current-group())"/> 本书
</xsl:for-each-group>
<!-- 按价格区间分组 -->
<xsl:for-each-group select="book" group-by="floor(price div 50)*50">
<h3>¥<xsl:value-of select="current-grouping-key()"/> -
<xsl:value-of select="current-grouping-key() + 49"/> 区间</h3>
</xsl:for-each-group>
六、一句话总结
新手用
<xsl:for-each>能快速上手
老手用<xsl:apply-templates>+<xsl:for-each-group>才能写出优雅、高性能、可维护的 XSLT
七、30 秒挑战(来真的!)
把下面这个 XML 变成:
刘慈欣(2本):
• 三体
• 三体II:黑暗森林
余华(1本):
• 活着
<books>
<book><author>刘慈欣</author><title>三体</title></book>
<book><author>余华</author><title>活着</title></book>
<book><author>刘慈欣</author><title>三体II:黑暗森林</title></book>
</books>
答案(一行分组 + 模板,优雅到爆):
<xsl:for-each-group select="books/book" group-by="author">
<xsl:value-of select="current-grouping-key()"/>(<xsl:value-of select="count(current-group())"/>本):<br/>
<xsl:for-each select="current-group()">
• <xsl:value-of select="title"/><br/>
</xsl:for-each>
<br/>
</xsl:for-each-group>
需要我现在用 <xsl:for-each> 或更优雅的模板方式帮你实现任何列表、报表、分组、CSV 导出?
直接甩 XML 过来,10 秒出成品!