Table template customization for printed output

The templates that generate tables in printed output are highly structured in DocBook XSL to facilitate customization. In addition to separate templates handling each table element, there are separate templates to handle different levels of processing for the table itself. These extra layers enable such features a floats, landscape tables, and table titles that are repeated after a page break with a (continued) label.

Table 30.3, “Print table templates” lists the principal templates used for format tables for printed output. The descriptions should help you decide at what level you might apply a customization. These descriptions apply to version 1.70.1 and later of the stylesheets.

Table 30.3. Print table templates

Stylesheet templateLocationDescription
match="table|informaltable"fo/formal.xslTop-level template that starts table processing. It calls a template named make.table.content and stores the result in a variable named table.content. It manages the subsequent layers of table processing, and finally outputs the table either directly or as a float.
name="make.table.content"fo/table.xslA short template that determines the table markup type (CALS or HTML markup). If it is a CALS table, it calls a template named calsTable. If the table uses HTML table markup, it applies templates in mode="htmlTable". The result of make.table.content is an fo:table element with all its children processed as the table content, but does not include the table title, footnotes, or other processing.
name="calsTable"fo/table.xslThis template processes each tgroup element into an fo:table element containing rows and columns, but not the title, footnotes, or other processing. It applies the table.table.properties attribute-set to the fo:table element.
mode="htmlTable"fo/htmltbl.xslThis template processes the content of the table into an fo:table element, to which it applies the table.table.properties attribute-set. It does not include the title, footnotes, or other processing.
name="table.layout"fo/table.xslThis template processes the result of make.table.content. It is a placeholder template that provides an opportunity for customization. It enables wrapping an fo:table in another table for purposes of layout (such as centering) or applying extensions such as XEP table-omit-initial-header to create "continued" titles after page breaks. By default, this template just copies the table content for the next stage.
name="table.block"fo/table.xsl

This template processes the result of table.layout. It does the following.

  • It creates an fo:block to contain the table title (if it has one), layout table, and table footnotes (if any).

  • It applies the table.properties attribute to the fo:block.

  • A table title is generated by formal.object.heading using the title element in a CALS table or the caption element in an HTML table.

  • It copies the table layout from the previous stage.

  • It calls table.footnote.block to handle any footnotes.

name="table.container"fo/table.xsl

This template processes the result of table.block. It adjusts the placement of the entire table block on the page.

  • If orient="land", it puts the table block in an fo:block-container rotated by 90 degrees.

  • If pgwide="1", it puts the table block in another fo:block that spans all columns and sets start-indent to zero.

  • If neither of those attributes are present, then it copies the table block through.

match="table|informaltable"fo/formal.xslThe end of this template processes the result of table.container. If the table as a floatstyle attribute, it wraps the table container in an fo:float and outputs that. If the table has no floatstyle attribute, it just copies the table container to the output.

While this sequence of templates may seem complicated, its purpose is to separate the various processing functions so they do not interfere with each other. The various layers of table processing are built up from the inside out, with each stage processing the result of the previous stage. This modular style makes for smaller templates that are easier to customize, and makes it easier to find where to apply a customization. The following section provides an example of table customization.

Table "continued" label

When a long table breaks across a page, it helps the reader if the table title is repeated at the top of the new page. But it helps even more if the title is labeled as "continued" so the reader knows the table is not starting there.

A "continued" label for long tables is not a standard feature of XSL-FO 1.0. It is supported in XSL-FO 1.1 using the retrieve-table-marker property. Since version 1.1 became a standard only in December 2006, support for its features is gradually being added to XSL-FO processors. You might check your XSL-FO processor documentation to see if that property is supported. If so, then a different customization is needed than the one described here. The DocBook XSL stylesheets will output 1.1 features when more processors support them.

However, if you are using the XEP processor from RenderX, then you can use an extension long provided by that processor. The extension is in the form of an attribute rx:table-omit-initial-header="true" that is applied to a layout table that wraps around the table content, but is inside the fo:block that contains the table title too.

This strangely-named attribute's function is to prevent a table header row from appearing on the first page of a table, and allowing it to appear on any subsequent pages if the table is long enough to break across a page boundary. You do not use it on the table's column headings, but rather on a special table header that repeats the table title along with the "continued" label. By omitting it on the first page of the table, you get the behavior you want.

The additional table header is not in the original fo:table, but in a wrapper table around it. The wrapper table has one column, the width of the entire table, one header cell for the continued title, and one body cell to contain the original fo:table. When such a table breaks across the page, the new page will display the continued title, a repeat of the original table column headings, and then continue the table rows.

This feature is applied using a customization of the template named table.layout described in the previous section.

Example 30.7. Table "continued" customization for XEP

<xsl:template name="table.layout">  1
  <xsl:param name="table.content"/>  2

  <xsl:choose>
    <xsl:when test="$xep.extensions = 0 or self::informaltable">  3
      <xsl:copy-of select="$table.content"/>
    </xsl:when>
    <xsl:otherwise>
      <fo:table rx:table-omit-initial-header="true">  4
        <fo:table-header start-indent="0pt">
          <fo:table-row>
            <fo:table-cell>
              <fo:block xsl:use-attribute-sets="formal.title.properties">  5
                <xsl:apply-templates select="." mode="object.title.markup"/>
                <fo:inline font-style="italic">
                  <xsl:text> (continued) </xsl:text>  6
                </fo:inline>
              </fo:block>
            </fo:table-cell>
          </fo:table-row>
        </fo:table-header>
        <fo:table-body start-indent="0pt">
          <fo:table-row>
            <fo:table-cell>
              <xsl:copy-of select="$table.content"/>  7
            </fo:table-cell>
          </fo:table-row>
        </fo:table-body>
      </fo:table>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:attribute-set name="table.properties">
  <xsl:attribute name="keep-together.within-column">auto</xsl:attribute> 8
</xsl:attribute-set>

1

Customize the placeholder template named table.layout from fo/table.xsl.

2

The already-processed table is passed in to the template as the table.content template parameter. This template forms a wrapper around that content.

3

If you are not using XEP, or if this is an informaltable (no title), then just copy the table content.

4

Start the wrapper table and add the extension attribute that is highlighted. Be sure to add the xmlns:rx namespace declaration to the top of your customization layer or the extension attribute will generate an error.

5

Create an fo:block to contain the title and continued label, using the formal.title.properties to format the block. The title is generated by processing the current table in mode="object.title.markup, which will include the number label and title.

6

Add a "continued" label, in this case formatting it with italic.

7

Copy the original table content into the single body cell of the wrapper table.

8

For long tables, you might want to set the keep-together.within-column property to auto to permit tables to break. If you do not make that change, then tables inherit the keep value of always from the formal.object.properties attribute-set. Trying to keep long tables together usually results in large white gaps on pages where a table might have started but it did not entirely fit.