You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改XSL-FO样式表在A4页高效放置多份发票(Apache FOP)

问题根源

你当前的样式表中,每个<Invoice_Download>都会生成独立的<fo:page-sequence>,这是导致每份发票独占一页的核心原因——每个page-sequence对应PDF里的一页(即便发票内容仅占1/3页面)。

解决方案

要实现多发票紧凑排版且不拆分,需把所有发票放在**同一个page-sequence**中,同时给每个发票的容器块添加不拆分规则。具体修改如下:

1. 调整根模板,统一生成单个page-sequence

将原来分散生成多个page-sequence的逻辑,改为在一个page-sequence的flow里渲染所有发票,同时保留第一页显示标题的页眉规则:

<xsl:template match="/">
  <fo:root>
    <fo:layout-master-set>
      <fo:simple-page-master master-name="invoice-page" page-width="21cm" margin="0.5cm">
        <fo:region-body margin="1cm" />
        <fo:region-before extent="3cm" />
        <fo:region-after extent="0.5cm" />
      </fo:simple-page-master>
      <!-- 区分第一页与后续页的模板引用,实现仅第一页显示标题 -->
      <fo:page-sequence-master master-name="invoice-sequence">
        <fo:repeatable-page-master-alternatives>
          <fo:conditional-page-master-reference master-reference="invoice-page" page-position="first" />
          <fo:conditional-page-master-reference master-reference="invoice-page" />
        </fo:repeatable-page-master-alternatives>
      </fo:page-sequence-master>
    </fo:layout-master-set>

    <!-- 仅创建一个page-sequence,承载所有发票内容 -->
    <fo:page-sequence master-reference="invoice-sequence">
      <fo:static-content flow-name="xsl-region-before">
        <fo:block text-align="center" font-size="18pt">
          <xsl:if test="page-position()='first'">INVOICES</xsl:if>
        </fo:block>
      </fo:static-content>
      <fo:flow flow-name="xsl-region-body">
        <xsl:apply-templates select="Download/Invoice_Download"/>
      </fo:flow>
    </fo:page-sequence>
  </fo:root>
</xsl:template>

2. 修改Invoice_Download模板,生成可堆叠的发票块

去掉原模板中的<fo:page-sequence>,改为生成包裹发票内容的块,并添加keep-together.within-page="always"确保整个发票不被拆分到两页:

<xsl:template match="Invoice_Download">
  <!-- 用block包裹发票内容,添加不拆分规则与间距区分不同发票 -->
  <fo:block keep-together.within-page="always" margin-bottom="1cm">
    <!-- 替换为你原来的发票具体内容 -->
    ...........
  </fo:block>
</xsl:template>

关键说明

  • 单个page-sequence:所有发票都在同一个page-sequence的flow中,Apache FOP会自动将能放下的发票排在同一页,空间不足时自动分页。
  • keep-together.within-page="always":强制每个发票作为完整整体,不会被拆分到两页。
  • 页眉控制:通过page-position()='first'实现仅第一页显示"INVOICES"标题,后续页页眉为空,匹配原需求。
完整修改后的样式表
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

  <xsl:template match="/">
    <fo:root>
      <fo:layout-master-set>
        <fo:simple-page-master master-name="invoice-page" page-width="21cm" margin="0.5cm">
          <fo:region-body margin="1cm" />
          <fo:region-before extent="3cm" />
          <fo:region-after extent="0.5cm" />
        </fo:simple-page-master>
        <fo:page-sequence-master master-name="invoice-sequence">
          <fo:repeatable-page-master-alternatives>
            <fo:conditional-page-master-reference master-reference="invoice-page" page-position="first" />
            <fo:conditional-page-master-reference master-reference="invoice-page" />
          </fo:repeatable-page-master-alternatives>
        </fo:page-sequence-master>
      </fo:layout-master-set>

      <fo:page-sequence master-reference="invoice-sequence">
        <fo:static-content flow-name="xsl-region-before">
          <fo:block text-align="center" font-size="18pt">
            <xsl:if test="page-position()='first'">INVOICES</xsl:if>
          </fo:block>
        </fo:static-content>
        <fo:flow flow-name="xsl-region-body">
          <xsl:apply-templates select="Download/Invoice_Download"/>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>

  <xsl:template match="Invoice_Download">
    <fo:block keep-together.within-page="always" margin-bottom="1cm">
      <!-- 替换为你的发票具体内容 -->
      ...........
    </fo:block>
  </xsl:template>
</xsl:stylesheet>

内容的提问来源于stack exchange,提问作者ashish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 13:30:29