XSL-FO 列表(fo:list-block)最全实战手册
(2025 年发票、合同、报表、图书目录里天天都在用的那一套写法)
一句话记住:
XSL-FO 没有 <ul><ol><dl>,只有一种万能列表元素:<fo:list-block>,所有项目符号、数字、字母、中文序号、自定义图片序号,全靠它搞定。
1. 核心结构(永远记住这三层)
xml
<fo:list-block provisional-distance-between-starts="8mm" <!-- 符号到正文的距离 -->
provisional-label-separation="2mm" <!-- 符号和正文之间的空隙 -->
space-after="10pt">
<fo:list-item>
<fo:list-item-label end-indent="label-end()"> <!-- 放项目符号或编号 -->
<fo:block>•</fo:block> <!-- 或 1. ① 第一条 等 -->
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()"> <!-- 放正文内容 -->
<fo:block>这里是第一条内容,可以很长很长自动换行对齐。</fo:block>
</fo:block>
</fo:list-item-body>
</fo:list-item>
<!-- 更多 list-item -->
</fo:list-block>
2. 2025 年最常用的 10 种列表样式(直接复制)
| 类型 | list-item-label 内容 | 推荐距离参数 | 典型场景 |
|---|---|---|---|
| 实心圆点(最常见) | <fo:block>•</fo:block> |
distance=7mm | 普通条款、注意事项 |
| 空心圆 | <fo:block>◦</fo:block> |
distance=7mm | 二级列表 |
| 中文数字序号 | <fo:block><fo:inline font-weight="bold">1.</fo:inline></fo:block> |
distance=10mm | 合同条款 |
| 自动编号(推荐!) | <fo:block><fo:inline font-family="SimSun"><fo:leader leader-pattern="use-content" leader-length="0pt"/>(<fo:counter name="item"/>)</fo:inline></fo:block> |
distance=12mm | 报表、规格书 |
| ① ② ③ 带圈数字 | <fo:block>①</fo:block>(用 Windows 私用区字符) |
distance=9mm | 发票、银行表单 |
| 一、二、三... | <fo:block>一、</fo:block> |
distance=12mm | 正式文件 |
| (1)(2)(3) 带括号数字 | <fo:block>(<fo:counter name="item"/>)</fo:block> |
distance=10mm | 技术文档 |
| 自定义图片符号 | <fo:external-graphic src="url('bullet-star.png')" width="5mm"/> |
distance=8mm | 高端品牌合同 |
| 左符号右对齐数字 | 用 fo:table 强行实现(后面给模板) | --- | 目录页(最难的) |
| 多级嵌套列表 | list-block 里再套 list-block | 每级 distance 递增 8mm | 技术手册、投标书 |
3. 推荐最强自动编号写法(2025 年主流)
xml
<fo:list-block provisional-distance-between-starts="12mm"
provisional-label-separation="3mm"
space-before="8pt" space-after="8pt">
<xsl:for-each select="item">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block text-align="end" font-weight="bold">
<xsl:number format="1." level="any" count="item"/>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block text-align="justify">
<xsl:value-of select="."/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
4. 终极目录页写法(左标题 右页码点线对齐)
xml
<fo:list-block provisional-distance-between-starts="140mm"
provisional-label-separation="5mm">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>1. 公司简介</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block text-align="right">
<fo:leader leader-pattern="dots" leader-length="100%"/>
<fo:page-number-citation ref-id="section1"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
5. 多级嵌套完美写法(合同、投标书最常见)
xml
<!-- 一级 -->
<fo:list-block provisional-distance-between-starts="15mm">
<fo:list-item>
<fo:list-item-label end-indent="label-end()"><fo:block>第<fo:counter name="lvl1" format="一"/>条</fo:block></fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>总则......</fo:block>
<!-- 二级嵌套 -->
<fo:list-block provisional-distance-between-starts="25mm" space-before="4pt">
<fo:list-item>
<fo:list-item-label end-indent="label-end()"><fo:block><fo:counter name="lvl2" format="1."/> </fo:block></fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>二级条款内容......</fo:block>
<!-- 三级嵌套 -->
<fo:list-block provisional-distance-between-starts="35mm">
<fo:list-item>
<fo:list-item-label end-indent="label-end()"><fo:block>(<fo:counter name="lvl3" format="1"/>)</fo:block></fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>三级条款......</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
6. 防坑终极表
| 问题 | 正确解决方式 |
|---|---|
| 项目符号和正文不对齐 | 必须写 provisional-distance-between-starts 和 label-end()/body-start() |
| 编号不连续 | 用同一个计数器名称,或用 xsl:number |
| 长内容换行后符号只出现第一行 | 正常!XSL-FO 标准就是这样设计 |
| 想让符号也换行对齐 | 改用 fo:table 实现(极少人这么干) |
| 中文"、"被挤到行首 | 加 linefeed-treatment="preserve" 到 fo:block |
一句话总结
所有列表全部用 fo:list-block + list-item + label/body 三层结构,
自动编号用 xsl:number 或 fo:counter ,
目录点线用 fo:leader ,
多级嵌套就是层层套 list-block。
需要我直接发你 5 个完整可运行模板吗?
- 增值税发票「购买方注意事项」列表
- 银行对账单「交易明细」带圈数字列表
- 投标书三级条款嵌套列表
- 图书目录(左标题右页码点线)
- 合同条款(第×条、第×款、(×))完美嵌套
说一声,10 秒发你。