XSLT 3.0使用accumulator实现脚注累积换行及重置问题求解
XSLT 实现XML带分页脚注转换方案
问题根因
实现失效的两个核心原因:
- accumulator规则默认在节点开始标签阶段触发,直接给eop配置start阶段的清空规则,会导致脚注还没输出就被重置
- 累积脚注时如果拼接纯文本字符串,后续添加的换行、div标签会被当成普通文本转义,无法实现独占一行的效果
具体实现代码
首先声明可流式处理的累积器,注意区分eop标签不同阶段的处理逻辑:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes"/> <!-- 声明notes累积器,存储类型为节点序列,初始值为空序列 --> <xsl:accumulator name="notes" as="node()*" initial-value="()"> <xsl:accumulator-rule match="note" phase="start" select="$value, ."/> <!-- eop开始阶段保留累积值,供输出脚注使用 --> <xsl:accumulator-rule match="eop" phase="start" select="$value"/> <!-- eop结束阶段再清空累积器,此时脚注已经完成输出 --> <xsl:accumulator-rule match="eop" phase="end" select="()"/> </xsl:accumulator> <!-- 全局启用累积器 --> <xsl:mode use-accumulators="notes"/> <!-- 根节点输出HTML基础结构 --> <xsl:template match="/"> <html> <body> <xsl:apply-templates/> <!-- 处理最后一页没有eop标签的情况,输出剩余脚注 --> <div class="footnotes"> <xsl:for-each select="accumulator-after('notes')"> <div class="footnote-item"> <xsl:apply-templates select="node()"/> </div> </xsl:for-each> </div> </body> </html> </xsl:template> <!-- 正文中的note显示为上标序号 --> <xsl:template match="note"> <sup> <xsl:number count="note" from="eop" level="any"/> </sup> </xsl:template> <!-- 匹配eop标签,输出当前页脚注和分页符 --> <xsl:template match="eop"> <div class="footnotes"> <xsl:for-each select="accumulator-before('notes')"> <div class="footnote-item"> <xsl:number count="note" from="eop" level="any"/>. <xsl:apply-templates select="node()"/> </div> </xsl:for-each> </div> <div style="page-break-after: always;"></div> </xsl:template> </xsl:stylesheet>
效果说明
- 每碰到eop标签时,会自动把当前页从上个分页符到当前eop之间的所有note收集起来,每条脚注用独立div包裹,默认独占一行
- 累积器只会在eop标签处理完成后才清空,不会出现脚注没输出就被重置的问题
- 兼容最后一页没有eop标签的边界情况,会自动输出最后一页剩余的所有脚注
- 脚注序号自动按页重置,符合常规文档脚注编号规则
内容的提问来源于stack exchange,提问作者OrYo
相关产品推荐
相关产品推荐

