多fo:marker类下fo:retrieve-marker调用逻辑及边界影响问询
XSL-FO标记检索与页脚渲染问题解答
问题列表
- 当页脚定义了多个
fo:retrieve-marker,且fo:flow flow-name="xsl-region-body"中按不同顺序实现了对应的3种fo:marker类时,retrieve-position、retrieve-boundary如何决定调用哪个retrieve-class-name,检索逻辑是否受其他因素影响?
- 当页脚定义了多个
- 对比CASE A和CASE B两种
fo:marker排列顺序的情况,输出会产生哪些差异?
- 对比CASE A和CASE B两种
- 是否存在可在页脚调用后运行时获取
fo:retrieve-marker属性、对应区域的函数,以便通过测试打印相关属性和区域来深入理解?
- 是否存在可在页脚调用后运行时获取
- 当将页脚定义中
retrieve-class-name="continued"的retrieve-boundary从page改为page-sequence后,对两种CASE的输出有何影响,需明确page-sequence边界的作用?
- 当将页脚定义中
相关代码定义
原页脚定义
<!--Footer def:--> <fo:static-content flow-name="second-footer"> <fo:retrieve-marker retrieve-class-name="lastPage" retrieve-position="last-starting-within-page" retrieve-boundary="page"/> <fo:retrieve-marker retrieve-class-name="continuedLine" retrieve-position="last-starting-within-page" retrieve-boundary="document"/> <fo:retrieve-marker retrieve-class-name="continued" retrieve-position="last-starting-within-page" retrieve-boundary="page"/> <fo:block> TEST </fo:block> </fo:static-content>
CASE A
<!--fo:flow flow-name="xsl-region-body" started--> <fo:marker marker-class-name="continued"> <xsl:call-template name="somePageTemp"/> </fo:marker> <fo:marker marker-class-name="lastPage"> <fo:block/> </fo:marker> <!--Make page 1 body template--> <!--Page break--> <fo:marker marker-class-name="continuedLine"> <fo:block> <fo:leader leader-pattern="rule"/> </fo:block> </fo:marker> <!--Make page 2 body template-->
CASE B
<!--fo:flow flow-name="xsl-region-body" started--> <fo:marker marker-class-name="continued"> <xsl:call-template name="somePageTemp"/> </fo:marker> <fo:marker marker-class-name="lastPage"> <fo:block/> </fo:marker> <fo:marker marker-class-name="continuedLine"> <fo:block> <fo:leader leader-pattern="rule"/> </fo:block> </fo:marker> <!--Make page 1 body template--> <!--Page break--> <!--Make page 2 body template-->
修改后的页脚定义
<!--Footer def:--> <fo:static-content flow-name="second-footer"> <fo:retrieve-marker retrieve-class-name="lastPage" retrieve-position="last-starting-within-page" retrieve-boundary="page"/> <fo:retrieve-marker retrieve-class-name="continuedLine" retrieve-position="last-starting-within-page" retrieve-boundary="document"/> <fo:retrieve-marker retrieve-class-name="continued" retrieve-position="last-starting-within-page" retrieve-boundary="page-sequence"/> <fo:block> TEST </fo:block> </fo:static-content>
问题解答
1. 标记检索逻辑说明
检索逻辑按以下优先级执行,同时受额外因素影响:
- 精确匹配类名:首先筛选出所有
marker-class-name与retrieve-class-name完全一致的fo:marker。 - 限定检索范围:通过
retrieve-boundary缩小检索范围:page:仅检索当前页内的标记page-sequence:检索当前页面序列(page-sequence)内的所有页面document:检索整个文档内的所有页面
- 筛选位置匹配的标记:通过
retrieve-position在范围内选择符合位置条件的标记,last-starting-within-page表示选择起始点落在当前页内的最后一个对应标记。 - 其他影响因素:
- 标记在流中的出现顺序:同范围同位置的标记,取流中最后出现的那个
- 分页位置:标记是否被分页符分割到不同页面,决定是否属于当前页的检索范围
- FO处理器实现细节:部分处理器对标记的缓存、匹配逻辑有细微差异
2. CASE A与CASE B的输出差异
两者核心差异在于continuedLine标记的分页位置,导致页脚中该标记的显示情况不同:
- CASE A:
continuedLine标记位于分页符之后,属于第2页的流内容:- 第1页页脚:当前页内无
continuedLine标记,因此该检索项无内容 - 第2页页脚:当前页内有
continuedLine标记,显示水平线(fo:leader)
- 第1页页脚:当前页内无
- CASE B:
continuedLine标记位于分页符之前,属于第1页的流内容:- 第1页页脚:当前页内有
continuedLine标记,显示水平线 - 第2页页脚:当前页内无
continuedLine标记,因此该检索项无内容
- 第1页页脚:当前页内有
其余两个标记(lastPage、continued)的输出在两种CASE中完全一致:第1页页脚显示对应内容,第2页页脚无对应标记内容。
3. 运行时测试与调试方法
原生XSL-FO规范未提供直接的运行时查询函数,但可通过以下方式间接测试:
- 添加调试文本:在
fo:retrieve-marker内部嵌入固定调试内容,通过是否显示标记内容+调试文本判断是否命中:<fo:retrieve-marker retrieve-class-name="lastPage" retrieve-position="last-starting-within-page" retrieve-boundary="page"> <fo:block>【调试】class=lastPage, boundary=page</fo:block> </fo:retrieve-marker> - 使用处理器调试工具:
- Apache FOP:添加
-dump参数输出格式化过程的中间数据,包含标记检索记录 - RenderX XEP:开启日志选项打印标记匹配细节
- Apache FOP:添加
- 自定义扩展:部分FO处理器支持扩展(如FOP的Java扩展),可编写代码获取标记匹配的内部信息
4. 修改retrieve-boundary为page-sequence的影响
首先明确page-sequence边界的作用
page-sequence是XSL-FO中一组共享相同页面布局的连续页面,一个文档可包含多个独立的page-sequence。retrieve-boundary="page-sequence"表示检索范围被限制在当前所在的page-sequence内,不会跨page-sequence检索;而page仅限制在当前页,document则覆盖整个文档。
对两种CASE的输出影响
由于原retrieve-position仍为last-starting-within-page(要求标记起始于当前页),修改边界后对两种CASE的输出无明显变化:
- 第1页页脚:当前页内存在
continued标记,无论边界是page还是page-sequence,都会检索到该标记并显示somePageTemp内容 - 第2页页脚:当前页内无
continued标记,即使page-sequence范围内存在第1页的标记,也因不符合starting-within-page的位置要求,无法被检索到,因此无内容
若将retrieve-position改为last,则两种CASE的第2页页脚都会检索到page-sequence内最后一个continued标记(即第1页的标记),从而显示somePageTemp内容。
内容的提问来源于stack exchange,提问作者Rito Sarkar
相关产品推荐
相关产品推荐

