Print TOC control

The main features for controlling tables of contents are described in the section “Tables of contents (TOC)”. This section describes features specific to print output.

Page margins

You can adjust the page margins for a table of contents by customizing the toc.margin.properties attribute set. Here is what the default looks like:

<xsl:attribute-set name="toc.margin.properties">
  <xsl:attribute name="space-before.minimum">0.5em</xsl:attribute>
  <xsl:attribute name="space-before.optimum">1em</xsl:attribute>
  <xsl:attribute name="space-before.maximum">2em</xsl:attribute>
  <xsl:attribute name="space-after.minimum">0.5em</xsl:attribute>
  <xsl:attribute name="space-after.optimum">1em</xsl:attribute>
  <xsl:attribute name="space-after.maximum">2em</xsl:attribute>
</xsl:attribute-set>

These properties don't change the margins for the page-master, but for the fo:block that contains the table of contents on the page. The space-before values add space above the TOC and space-after add space below the toc. You would use start-indent to indent from left, and end-indent to indent from the right. A customized version might look like the following:

<xsl:attribute-set name="toc.margin.properties">
  <xsl:attribute name="start-indent">0.5in</xsl:attribute>
  <xsl:attribute name="end-indent">0.5in</xsl:attribute>
</xsl:attribute-set>

As with all attribute-sets, your customized properties are merged with the default set. You could add other properties that would apply to the whole TOC block. For example, a TOC in an article does not have a page break after it by default. This example would add that page break.

<xsl:attribute-set name="toc.margin.properties">
  <xsl:attribute name="break-after">page</xsl:attribute>
  </xsl:attribute-set>

If you want to change the page layout beyond these properties, you will need to add a customized page-master, in this case for the lot (list of titles) page class. See the section “Custom page design” for a description of how to do that. In addition to a new page master, you will need to customize the select.user.pagemaster template to select your new page master file during processing.

TOC title

The Table of Contents title that appears at the top of a TOC is turned on or off with the generate.toc parameter. See the section “Which components have a TOC” to see how to change that parameter.

The title text in a table of contents is generated text, using the TableofContents key word. For English, the text comes from the gentext file common/en.xml, where the text associated with the key word is "Table of Contents". You can change it for a given language in a customization layer with something like this:

<xsl:param name="local.l10n.xml" select="document('')"/> 
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0"> 
  <l:l10n language="en"> 
    <l:gentext key="TableofContents" text="Contents"/>
  </l:l10n>
</l:i18n>

The formatting of the title is controlled by the same machinery that controls title pages. While a TOC could have a complete title page, the default behavior is just to start a page and put the title at the top. If you want to change how the title is formatted, then you will need to customize the titlepage spec file and generate a new titlepage stylesheet module. See the section “Title page spec file” information on how to do that. Specifically, you will want to change the following entry in the spec file:

<t:titlepage element="table.of.contents" wrapper="fo:block">
  <t:titlepage-content side="recto">
    <title
           force="1"
           named-template="gentext"
           param:key="'TableofContents'"
           fo:space-before.minimum="1em"
           fo:space-before.optimum="1.5em"
           fo:space-before.maximum="2em"
           fo:space-after="0.5em"
           fo:margin-left="{$title.margin.left}"
           fo:font-size="&hsize3;"
           fo:font-weight="bold"
           fo:font-family="{$title.font.family}"/>
  </t:titlepage-content>

The spec file needs to be processed into a stylesheet module that gets included in your customization layer.

If you don't want to generate a new titlepage spec file just to modify the table of contents title, you can instead replace the template named table.of.contents.titlepage. If your customization has a template of this name, then it will override the processing done by the regular title page machinery. You may need to give your version a priority attribute with a value of greater than zero, in case there is a problem with import precedence. The template must get the title using the gentext template, and then generate an fo:block with the appropriate properties. After outputting the title, it must close the fo:block. For example:

<xsl:template name="table.of.contents.titlepage" priority="1">
  <fo:block xsl:use-attribute-sets="section.title.level1.properties"
            space-before="1in"
            space-before.conditionality="retain"
            space-after="12pt"
            border-bottom="0.5pt solid black">
    <xsl:call-template name="gentext">
      <xsl:with-param name="key" select="'TableofContents'"/>
    </xsl:call-template>
  </fo:block>
</xsl:template>

The space-before.conditionality="retain" property forces the formatter to use the specified space-before value, even though it is at the top of the page where it would normally be ignored.

Styling print TOC entries

An entry in a table of contents is produced by applying templates that have mode="toc" and that match the element associated with that entry. So the template that formats an entry for a sect1 title would start with:

<xsl:template match="sect1" mode="toc">

These templates are located in the fo/autotoc.xsl stylesheet file. They are not good candidates for customization because they are pretty complex. The complexity comes from the recursive nature of processing all the elements in the document in the toc mode. Each mode="toc" template generates the entry for its element, and then checks to see if the element has children that should appear in the TOC. If so, then it increments the indent by the amount of the parameter toc.indent.width and applies templates in toc mode to process the children.

If you want to change the way indenting of entries is handled (beyond just adjusting the parameter value), then you would need to customize the mode="toc" template that matches the element whose children you want to change.

The template that can be customized more easily is named toc.line, because it formats a single entry of a TOC. By default, it formats all TOC lines the same, since the left indent has been set by the template that called toc.line. If you want to customize certain TOC entries, then your customization would need to test for the name of the context node and act accordingly. For example, if you wanted just chapter titles in the TOC to appear in bold, then add the following version of toc.line to your customization:

<xsl:template name="toc.line">
  <xsl:variable name="id">
    <xsl:call-template name="object.id"/>
  </xsl:variable>

  <xsl:variable name="label">
    <xsl:apply-templates select="." mode="label.markup"/>
  </xsl:variable>

  <fo:block text-align-last="justify"
            end-indent="{$toc.indent.width}pt"
            last-line-end-indent="-{$toc.indent.width}pt">
    <fo:inline keep-with-next.within-line="always">
      <xsl:choose>
        <xsl:when test="self::chapter">
          <xsl:attribute name="font-weight">bold</xsl:attribute>
        </xsl:when>
      </xsl:choose>
      <fo:basic-link internal-destination="{$id}">
        <xsl:if test="$label != ''">
          <xsl:copy-of select="$label"/>
          <xsl:value-of select="$autotoc.label.separator"/>
        </xsl:if>
        <xsl:apply-templates select="." mode="title.markup"/>
      </fo:basic-link>
    </fo:inline>
    <fo:inline keep-together.within-line="always">
      <xsl:text> </xsl:text>
      <fo:leader leader-pattern="dots"
                 leader-pattern-width="3pt"
                 leader-alignment="reference-area"
                 keep-with-next.within-line="always"/>
      <xsl:text> </xsl:text>
      <fo:basic-link internal-destination="{$id}">
        <fo:page-number-citation ref-id="{$id}"/>
      </fo:basic-link>
    </fo:inline>
  </fo:block>
</xsl:template>

The highlighted addition to the template tests for the element name, and adds the bold property if it is a chapter.

TOC page numbering

When a TOC page is started, it is assigned a format for its own page numbers. It gets the format by calling the template named page.number.format. That is a simple template that can be customized in a customization layer. Here is an example that changes the page numbering style of the TOC to 1, 2, 3 etc.

<xsl:template name="page.number.format">
  <xsl:param name="element" select="local-name(.)"/>
  <xsl:choose>
    <xsl:when test="$element = 'toc'">1</xsl:when>
    <xsl:when test="$element = 'preface'">i</xsl:when>
    <xsl:when test="$element = 'dedication'">i</xsl:when>
    <xsl:otherwise>1</xsl:otherwise>
  </xsl:choose>
</xsl:template>

Editable table of contents

You may need more control over a table of contents than is provided with the customization features in the stylesheets. In those situations, you may need to create a table of contents as an XML file that you can edit and process as part of your document. You can do this for the main table of contents in HTML processing, but not currently for FO output. Fortunately, you don't have write the TOC from scratch.

The extra stylesheet file html/maketoc.xsl will output a TOC document that has a main toc element that contains a set of tocentry elements. If you output that to a file, you can edit it and feed it back into the processing of your document. Here are steps to do that.

Using an editable table of contents

  1. Generate a table of contents XML file from your document. For example:

    xsltproc  -o customtoc.xml  html/maketoc.xsl  mybook.xml
    
  2. Edit the TOC file customtoc.xml as needed.

  3. Generate your document output by processing your document with the manual.toc parameter:

    xsltproc  -o mybook.html  \
        --stringparam manual.toc  customtoc.xml  \
        html/docbook.xsl  mybook.xml

The stylesheet parameter manual.toc identifies the filename of your editable XML TOC file. If you pass this parameter to the stylesheet during processing, it will use that file in place of the automatically generated TOC.

Note

If you regenerate your document, you may also have to re-edit the table of contents. Unless you can automate the changes with a script, using an editable TOC is efficient only for documents that rarely change.