how to keep table with header but allow page breaks inside table body in XSL-FO using FOP

Jens Wegar picture Jens Wegar · Nov 21, 2011 · Viewed 18.3k times · Source

I'm generating a PDF using Apache FOP and a XSL-FO stylesheet. In the PDF, I output headings (html equiv h1) which belong to a table, so should be kept together always. However, my tables may also contain so much data that they don't necessarily fit on one page.

The desired result is a rule set that allows a heading to be kept with the table and fit both on one page if possible, but if the table data is so long that it does not fit on one page, then page breaks would be inserted in the table while still keeping the heading element on the same page as the start of the table.

The solution I have right now does keep the heading and the table together, but I get an Content overflows error for the table data if everything does not fit onto one page. I was hoping that page-break-inside: avoid set on the table element would help with this, but apparently not... suggestions?

Example xsl (cut short for readability):

<!-- add test table with header that should stay on same page -->
<fo:block font-size="20pt" font-weight="bold">Table header</fo:block>

<fo:table keep-with-previous.within-page="always"
      page-break-inside="avoid" 
      table-layout="fixed" border-width="1mm" border-style="solid">
  <fo:table-column column-width="auto" />
  <fo:table-column column-width="30mm" />

  <fo:table-header text-align="center" background-color="silver">
    <fo:table-row>
      <fo:table-cell padding="1mm" border-width="1mm" border-style="solid">
    <fo:block>First name</fo:block>
      </fo:table-cell>
      <fo:table-cell padding="1mm" border-width="1mm" border-style="solid">
    <fo:block>Last name</fo:block>
      </fo:table-cell>
    </fo:table-row>
  </fo:table-header>
  <fo:table-body>
    <!-- the table-rows can be repeated N times, spanning several pages -->
    <fo:table-row >
      <fo:table-cell padding="1mm" border-width="1mm" border-style="solid">
    <fo:block>ab</fo:block>
      </fo:table-cell>
      <fo:table-cell padding="1mm" border-width="1mm" border-style="solid">
    <fo:block>cd</fo:block>
      </fo:table-cell>
    </fo:table-row>
    <!-- .... more table-row:s ---> 

Update on desired output

To better describe what result I'm looking for:

The result document contains both text paragraphs, headings and tables.

  1. If the amount of content is such that the table would have only one or two rows on the next page, then the xsl-fo should move the entire table and the heading to the next page provided that it fits on that page entirely.
  2. If on the other hand the table as so many rows that it wouldn't fit on an entirely new page anyway, then output should be started right away in the document flow, while still allowing the table to be split acros several pages.

If I remove page-break-inside="avoid", then I get a table that breaks across several pages nicely, but cases described in #1 would not be matched. I.e. it does not move a table and it's heading entirely to the next page if only a few rows would end up being moved to the next page. If I leave page-break-inside, then I get a content overflow problem with long tables, because rows that don't fit on the page are not moved to the next page.

I guess one of the basic problems is that my output tables are very dynamic in length and unfortunately I don't have any control over what amount of data gets produced into the tables.

Answer

Jeremias M&#228;rki picture Jeremias Märki · Nov 22, 2011

The CSS property page-break-inside="avoid" maps to the native FO property keep-together="always". This mapping is questionable IMO (but that's a different story). Anyway, I suggest you use the native FO property keep-together.within-column="1" instead of page-break-inside. That allows Apache FOP to break inside the table when absolutely necessary.