XML/XSL生成PDF时如何让blueTitle1标题与content内容保持同页
XSL-FO 实现标题与紧随正文同页方案
要实现role="blueTitle1"标题和后续role="content"正文不被分页拆分,直接使用XSL-FO原生的分页控制属性即可,不需要重构现有转换逻辑,以下是两种可直接落地的方案:
方案1:最小改动方案(推荐)
仅需给所有blueTitle1生成的fo:block标签添加keep-with-next.within-page="always"属性。
该属性的作用是禁止在当前标题块和紧邻的下一个内容块之间插入分页符,保证标题不会单独留在页面末尾、正文从下一页开始。
修改后的blueTitle1匹配规则代码如下:
<xsl:when test="@role = 'blueTitle1'"> <xsl:choose> <xsl:when test="@anchor"> <xsl:variable name="anchorLink" select="@anchor"/> <!-- 新增keep-with-next分页控制属性 --> <fo:block id="{$anchorLink}" font-size="14pt" line-height="13pt" color="#00a6ce" font-family="AvenirNextLTProBold" padding-top="0.7cm" keep-with-next.within-page="always"> <xsl:apply-templates /> </fo:block> </xsl:when> <xsl:otherwise> <!-- 新增keep-with-next分页控制属性 --> <fo:block font-size="14pt" line-height="13pt" color="#00abd2" font-family="AvenirNextLTProBold" padding-top="0.7cm" keep-with-next.within-page="always"> <xsl:apply-templates /> </fo:block> </xsl:otherwise> </xsl:choose> </xsl:when>
content对应的原有规则不需要做任何修改。
适用场景:正文长度不固定,仅需要避免标题孤行,允许正文过长时在内部分页。所有主流XSL-FO渲染引擎(Apache FOP、Antenna House、RenderX XEP)均支持该属性。
方案2:整体包裹方案(严格同页场景)
如果需要标题和正文的组合整体尽可能不拆分,可以用带keep-together属性的块容器将两个条目包裹为一个整体:
- 新增匹配规则,优先识别「
blueTitle1后紧邻content」的组合场景 - 外层套
<fo:block-container keep-together.within-page="always">容器 - 在容器内一次性生成标题和正文块,避免正文被单独匹配渲染
核心实现代码参考:
<!-- 优先匹配标题+正文的组合场景 --> <xsl:when test="@role = 'blueTitle1' and following-sibling::entry[1]/@role = 'content'"> <fo:block-container keep-together.within-page="always"> <!-- 复用原有标题生成逻辑 --> <xsl:choose> <xsl:when test="@anchor"> <xsl:variable name="anchorLink" select="@anchor"/> <fo:block id="{$anchorLink}" font-size="14pt" line-height="13pt" color="#00a6ce" font-family="AvenirNextLTProBold" padding-top="0.7cm"> <xsl:apply-templates /> </fo:block> </xsl:when> <xsl:otherwise> <fo:block font-size="14pt" line-height="13pt" color="#00abd2" font-family="AvenirNextLTProBold" padding-top="0.7cm"> <xsl:apply-templates /> </fo:block> </xsl:otherwise> </xsl:choose> <!-- 直接渲染紧随的正文内容,加mode避免重复匹配 --> <xsl:apply-templates select="following-sibling::entry[1]" mode="inlineRender"/> </fo:block-container> </xsl:when> <!-- 原有单独的blueTitle1、content匹配规则保留,新增mode匹配避免正文重复渲染 --> <xsl:template match="entry[@role='content']" mode="inlineRender"> <!-- 复用原有content的fo:block生成逻辑即可 --> </xsl:template>
注意:如果标题+正文的总高度超过单页可容纳高度,渲染引擎仍会自动分页,不会强制内容溢出页面。
常见问题说明
- 配置后如果出现标题被自动挤到下一页、上一页底部留空白的情况,属于正常分页逻辑,是为了满足同页约束的自动调整
- 不要额外添加
force-page-count类的强制分页参数,会打乱正常文档流 - 如果需要调整同页约束的优先级,可以将属性值从
always替换为整数(数值越大优先级越高),平衡同页要求和页面留白的平衡
内容的提问来源于stack exchange,提问作者user17710829
相关产品推荐
相关产品推荐

