如何用XSLT实现XSL-FO固定位置表格分页(首页5行+续页提示)
固定位置表格的分页与提示实现方案
需求说明
需在**绝对定位的<fo:block-container>**中展示行数不固定的表格:
- 首页仅显示表头+最多5行数据,若数据总行数超过5,在表格末尾添加「续见下页」提示
- 剩余数据在新页面的对应位置生成完整表格(含表头+剩余数据行)
- 最终用Apache FOP生成AFP/PDF文件
实现思路
由于绝对定位容器无法依赖FOP自动分页机制,需通过XSLT手动拆分数据:
- 统计
InstallmentPlan节点总数,判断是否需要分页 - 首页表格仅渲染前5条数据,根据总数判断是否添加提示行
- 若存在剩余数据,生成新页面并渲染表头+剩余数据行
完整代码示例
首页固定位置表格
<fo:block-container border="solid 1px" absolute-position="absolute" left="3.09in" top="2.95in" width="4.765in" height="1.1in" overflow="hidden"> <fo:table table-layout="fixed" width="100%"> <fo:table-body> <!-- 表头行 --> <fo:table-row> <fo:table-cell> <fo:block padding-left="2.0mm" padding="2pt" font-family="TelenorTFBold" font-size="11pt" font-weight="normal" fox:border-before-start-radius="5pt" fox:border-before-end-radius="5pt" fox:border-after-start-radius="5pt" fox:border-after-end-radius="5pt" background-color="#f8f8f8"> <xsl:call-template name="LabelText"> <xsl:with-param name="Code" select="concat($language, 'Number')"/> </xsl:call-template> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block padding-left="2.0mm" padding="2pt" font-family="TelenorTFBold" font-size="11pt" font-weight="normal" fox:border-before-start-radius="5pt" fox:border-before-end-radius="5pt" fox:border-after-start-radius="5pt" fox:border-after-end-radius="5pt" background-color="#f8f8f8"> <xsl:call-template name="LabelText"> <xsl:with-param name="Code" select="concat($language, 'duedate')"/> </xsl:call-template> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block text-align="right" padding-left="2.0mm" padding="2pt" font-family="TelenorTFBold" font-size="11pt" font-weight="normal" fox:border-before-start-radius="5pt" fox:border-before-end-radius="5pt" fox:border-after-start-radius="5pt" fox:border-after-end-radius="5pt" background-color="#f8f8f8"> <xsl:call-template name="LabelText"> <xsl:with-param name="Code" select="concat($language, 'Total')"/> </xsl:call-template> </fo:block> </fo:table-cell> </fo:table-row> <!-- 渲染前5条数据行 --> <xsl:for-each select="InstallmentPlan[position() <= 5]"> <fo:table-row> <fo:table-cell font-family="TelenorTF" font-size="7pt" font-weight="normal"> <fo:block padding-after="0.15cm" white-space-collapse="false"> <xsl:value-of select="InstallmentNumber"/> </fo:block> </fo:table-cell> <fo:table-cell font-family="TelenorTF" font-size="7pt" font-weight="normal"> <fo:block padding-after="0.15cm" white-space-collapse="false"> <xsl:value-of select="DueDate"/> </fo:block> </fo:table-cell> <fo:table-cell font-family="TelenorTF" font-size="7pt" font-weight="normal"> <fo:block text-align="right" padding-after="0.15cm" white-space-collapse="false"> <xsl:call-template name="format_amount"> <xsl:with-param name="amount" select="Amount"/> </xsl:call-template> </fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> <!-- 数据总数超过5时添加提示行 --> <xsl:if test="count(InstallmentPlan) > 5"> <fo:table-row> <fo:table-cell number-columns-spanned="3"> <fo:block text-align="right" padding-right="2.0mm" padding-top="2pt" font-family="TelenorTF" font-size="7pt"> 续见下页 </fo:block> </fo:table-cell> </fo:table-row> </xsl:if> </fo:table-body> </fo:table> </fo:block-container>
剩余数据的新页面渲染
在首页内容后添加以下代码处理剩余数据:
<!-- 存在剩余数据时生成新页面 --> <xsl:if test="count(InstallmentPlan) > 5"> <fo:page-sequence master-reference="你的页面模板名称"> <fo:flow flow-name="xsl-region-body"> <!-- 新页面表格容器,位置与首页保持一致 --> <fo:block-container border="solid 1px" absolute-position="absolute" left="3.09in" top="2.95in" width="4.765in"> <fo:table table-layout="fixed" width="100%"> <fo:table-body> <!-- 重复表头行 --> <fo:table-row> <fo:table-cell> <fo:block padding-left="2.0mm" padding="2pt" font-family="TelenorTFBold" font-size="11pt" font-weight="normal" fox:border-before-start-radius="5pt" fox:border-before-end-radius="5pt" fox:border-after-start-radius="5pt" fox:border-after-end-radius="5pt" background-color="#f8f8f8"> <xsl:call-template name="LabelText"> <xsl:with-param name="Code" select="concat($language, 'Number')"/> </xsl:call-template> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block padding-left="2.0mm" padding="2pt" font-family="TelenorTFBold" font-size="11pt" font-weight="normal" fox:border-before-start-radius="5pt" fox:border-before-end-radius="5pt" fox:border-after-start-radius="5pt" fox:border-after-end-radius="5pt" background-color="#f8f8f8"> <xsl:call-template name="LabelText"> <xsl:with-param name="Code" select="concat($language, 'duedate')"/> </xsl:call-template> </fo:block> </fo:table-cell> <fo:table-cell> <fo:block text-align="right" padding-left="2.0mm" padding="2pt" font-family="TelenorTFBold" font-size="11pt" font-weight="normal" fox:border-before-start-radius="5pt" fox:border-before-end-radius="5pt" fox:border-after-start-radius="5pt" fox:border-after-end-radius="5pt" background-color="#f8f8f8"> <xsl:call-template name="LabelText"> <xsl:with-param name="Code" select="concat($language, 'Total')"/> </xsl:call-template> </fo:block> </fo:table-cell> </fo:table-row> <!-- 渲染剩余数据行 --> <xsl:for-each select="InstallmentPlan[position() > 5]"> <fo:table-row> <fo:table-cell font-family="TelenorTF" font-size="7pt" font-weight="normal"> <fo:block padding-after="0.15cm" white-space-collapse="false"> <xsl:value-of select="InstallmentNumber"/> </fo:block> </fo:table-cell> <fo:table-cell font-family="TelenorTF" font-size="7pt" font-weight="normal"> <fo:block padding-after="0.15cm" white-space-collapse="false"> <xsl:value-of select="DueDate"/> </fo:block> </fo:table-cell> <fo:table-cell font-family="TelenorTF" font-size="7pt" font-weight="normal"> <fo:block text-align="right" padding-after="0.15cm" white-space-collapse="false"> <xsl:call-template name="format_amount"> <xsl:with-param name="amount" select="Amount"/> </xsl:call-template> </fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> </fo:table-body> </fo:table> </fo:block-container> <!-- 新页面其他内容 --> <fo:block>信息区域</fo:block> </fo:flow> </fo:page-sequence> </xsl:if>
关键说明
- 通过
count(InstallmentPlan)判断数据总数,控制提示和新页面的生成 - 用
position()筛选数据行,实现精准拆分 - 新页面的表格容器位置需与首页保持一致,确保视觉统一
- 若剩余数据仍需多分页,可重复上述逻辑(如每5行一页)
内容的提问来源于stack exchange,提问作者Pooja
相关产品推荐
相关产品推荐

