Tables of contents (TOC)

The DocBook stylesheets have several features for generating tables of contents. In addition to the traditional list of chapters and sections at the beginning of a book or article, you can optionally generate lists of figures, tables, examples, equations, and procedures. You can also generate mini tables of contents for each chapter or even each section, down to a section level of your choice.

Some aspects of customizing tables of contents can be controlled with parameters, and other require a customization layer.

Which components have a TOC

The DocBook XSL stylesheets use the generate.toc parameter to determine which elements have a TOC generated at the beginning of the element in the output. For print output or non-chunked HTML output, a single TOC at the beginning may suffice. But when you are generating chunked HTML files, you may want certain sublevels to provide TOCs to help orient the reader.

Although generate.toc is a parameter that can be set on the command line, it is a bit awkward to use that way because it can contain a lot of information. The default value of generate.toc (HTML version) is:

<xsl:param name="generate.toc">
appendix  toc,title
article/appendix  nop
article   toc,title
book      toc,title,figure,table,example,equation
chapter   toc,title
part      toc,title
preface   toc,title
qandadiv  toc
qandaset  toc
reference toc,title
sect1     toc
sect2     toc
sect3     toc
sect4     toc
sect5     toc
section   toc
set       toc,title
</xsl:param>

The parameter value is read as white-space separated pairs (leading whitespace is trimmed off). The first word of each pair is an element name, and the second word is a comma-separated list that specifies what kind of TOCs it should have. Most of them just use toc, which is a list of section titles. But the entry for the book element will also generate tables of figures, tables, examples, and equations. The word title triggers printing a title for the list, such as "Table of Contents". Use a value of nop to turn off all TOCs for an element. You can also turn off a TOC by removing the element entirely from the parameter.

You can change which elements have TOCs by putting a new version of this parameter in your customization layer. For example, to remove the TOC from the elements preface, part, qandadiv, qandaset, appendix, and sections, and remove the TOC title from chapter, use this parameter value:

<xsl:param name="generate.toc">
 appendix  nop
 article   toc,title
 book      toc,title,figure,table,example,equation
 chapter   toc
 part      nop
 preface   nop
 qandadiv  nop
 qandaset  nop
 reference toc,title
 section   nop
 set       toc
 </xsl:param>

If your document is a book and you only want a book-level TOC and no others, then you can use a very simple value:

<xsl:param name="generate.toc" select="'book toc'"/>

That is a space between book and toc, and don't forget the single quotes to make it a string. You can even set this simple value on the command line:

xsltproc  --stringparam generate.toc "book toc" ...

Because the list uses white space to separate items in the list, and then counts through the list to establish pairs of items, you have to follow a few rules with this parameter:

  • A "white space" includes any sequence of blanks spaces, tabs, and carriage returns. So you could put all the information on one line with single blanks between items. In fact, that is what the processor does using the normalize-space XSL function.

  • Don't leave a value blank, because that messes up the pairing. Either remove the element name or enter nop to turn off an element you leave in the list.

  • Don't insert spaces in a comma separated list like toc,figure,table. The spaces will mess up the pairing.

You can get even finer control of when TOCs are used by adding context information. For example, an article in a book can be treated differently from an article as a whole document. See the reference page for the generate.toc parameter for more information.

Note

Section TOCs are also controlled by the generate.section.toc.level parameter, which is by default set to zero. See the section “Turning on section TOCs”.

Levels in book and chapter TOCs

You can control how many nested levels of headings a TOC list should have. A book TOC always lists the titles for part and chapter elements, as well as any other components at the chapter level such as preface, appendix, glossary and index. A book TOC may also contain titles of sections within the chapters, depending on the value of the toc.section.depth parameter. If chapter TOCs are turned on by the generate.toc parameter, then what appears in the chapter TOC is completely controlled by the toc.section.depth parameter. The following table summarizes its effect on book and chapter TOCs.

Use the toc.section.depth parameter to indicate how many levels of section titles should appear in the TOCs. If you set it to a value of 3, for example, then TOCs will include up to sect3 titles. The default value is 2. The following table summarizes the effect of the parameter.

Table 9.1. How toc.section.depth affects book and chapter TOCs

toc.section.depthBook TOC includes:Chapter TOC includes:
0
chapter
No TOC
1
chapter
  sect1
sect1
2 (default)
chapter
  sect1
    sect2
sect1
  sect2
3
chapter
  sect1
    sect2
      sect3
sect1
  sect2
    sect3

If you use bridgehead titles in your document, you also have the option of including those titles in your TOCs. To do so, set the bridgehead.in.toc parameter to 1. Then all bridgehead titles will be included at the appropriate level in the TOC.

There is a different style of hierarchy for TOCs that the toc.max.depth parameter controls. In this style, each TOC regardless of where it is located has the same number of levels (if the content is there and the TOC is enabled with the generate.toc parameter). The toc.max.depth parameter controls the maximum number of levels in any TOC. This parameter first appeared in version 1.61 of the stylesheets, and only applies to HTML output. The following table summarizes the effect of the parameter.

Table 9.2. How toc.max.depth affects book and chapter TOCs (HTML output only)

toc.max.depthBook TOC includes:Chapter TOC includes:
0No TOCNo TOC
1
chapter
sect1
2
chapter
  sect1
sect1
  sect2
3
chapter
  sect1
    sect2
sect1
  sect2
    sect3

You will notice that both the book and chapter TOCs contain the same number of levels for each value of the parameter. The table assumes that the toc.section.depth parameter has been increased to at least 3. If not, then the default value of 2 would limit the chapter TOC in the last row to sect1 and sect2 entries. The default value of toc.max.depth is 7, so normally the toc.section.depth parameter is the limiting factor in a given TOC's depth.

Customized TOC levels

The stylesheet parameters described in the section “Levels in book and chapter TOCs” give you some control of what levels of headings appear in a book, chapter, and section TOCs. There are some combinations that cannot be achieved with just parameters and require template customization.

For example, you might want your book TOC in HTML to just list the chapter titles, and then rely on complete TOCs in each chapter to provide section titles. The following short customization does that.

<xsl:template match="preface|chapter|appendix|article" mode="toc">
  <xsl:param name="toc-context" select="."/>

  <xsl:choose>
    <xsl:when test="local-name($toc-context) = 'book'">
      <xsl:call-template name="subtoc">
        <xsl:with-param name="toc-context" select="$toc-context"/>
        <xsl:with-param name="nodes" select="foo"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="subtoc">
        <xsl:with-param name="toc-context" select="$toc-context"/>
        <xsl:with-param name="nodes"
              select="section|sect1|glossary|bibliography|index
                     |bridgehead[$bridgehead.in.toc != 0]"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

It is a copy of a template in html/autotoc.xsl, modified to add a choose statement. It processes the chapter element (and other elements) in mode="toc" to generate lines in your TOC. The $toc-context template parameter contains the element in which the TOC is appearing. So if you take the local-name() of that element and compare it to 'book', the template can take a different action. In this case, you tell it to select foo children of the chapter element, which will be an empty node set since there is no such element. Then the depth of the chapter toc can be controlled by the toc.section.depth parameter.

Turning on section TOCs

By default, sections do not have their own TOCs. But you can use parameters to turn on TOCs for sections and control what levels are listed. Section TOCs are particularly useful with chunked HTML output for which the user might need some context for complex documents.

Two parameters control which section levels have a TOC: generate.toc and generate.section.toc.level. You will notice that the default value of the generate.toc parameter described in the section “Which components have a TOC” includes entries for all the section levels, yet the default output does not have section TOCs. That is because a second parameter generate.section.toc.level also controls which section levels have a TOC. For example, if you set generate.section.toc.level to a value of 2, then you will get a TOC for all sect1 and sect2 elements, or their equivalents in nested section elements. Why two parameters? This arrangement lets you establish a style for which TOCs could appear at various section levels by modifying the complex generate.toc parameter in your customization layer. Then you can select the actual output level at runtime with the simple generate.section.toc.level parameter. Both parameters must enable a section level for its TOC to appear.

The depth of section levels that appear in a given section TOC is usually controlled by the toc.section.depth parameter. This parameter indicates the deepest section level that can appear in any TOC. It's default value of 2 means only sections up to sect2 will appear in any TOC. For HTML output, a second parameter toc.max.depth can be used to produce a different style of TOC hierarchy. This parameter indicates the maximum number of levels that appear in any TOC. A value of 2 means only up to two levels of titles will appear in any TOC, regardless of where the TOC appears.

The following two tables show how these two parameters affect section TOCs for various values of the generate.section.toc.level parameter.

Table 9.3. Section TOCs with toc.section.depth

generate.section.toc.leveltoc.section.depthsect1 TOC includes:sect2 TOC includes:sect3 TOC includes:sect4 TOC includes:
12
sect2
No TOC No TOC No TOC
3
sect2
  sect3
No TOC No TOC No TOC
4
sect2
  sect3
    sect4
No TOC No TOC No TOC
22
sect2
No TOC No TOC No TOC
3
sect2
  sect3
sect3
No TOC No TOC
4
sect2
  sect3
    sect4
sect3
  sect4
No TOC No TOC
32
sect2
No TOC No TOC No TOC
3
sect2
  sect3
sect3
No TOC No TOC
4
sect2
  sect3
    sect4
sect3
  sect4
sect4
No TOC

In some cases, there is no TOC because the TOC would be in a section level outside the range of the generate.section.toc.level parameter. In other cases, there is no TOC because the toc.section.depth parameter prevents it from having any entries. This table assumes the other parameter, toc.max.depth, has a value high enough to not interfere with the selection of levels.

Table 9.4. Section TOCs with toc.max.depth (HTML only)

generate.section.toc.leveltoc.max.depthsect1 TOC includes:sect2 TOC includes:sect3 TOC includes:sect4 TOC includes:
1 1
sect2
No TOC No TOC No TOC
2
sect2
  sect3
No TOC No TOC No TOC
3
sect2
  sect3
    sect4
No TOC No TOC No TOC
21
sect2
sect3
No TOC No TOC
2
sect2
  sect3
sect3
  sect4
No TOC No TOC
3
sect2
  sect3
    sect4
sect3
  sect4
    sect5
No TOC No TOC
31
sect2
sect3
sect4
No TOC
2
sect2
  sect3
sect3
  sect4
sect4
  sect5
No TOC
3
sect2
  sect3
    sect4
sect3
  sect4
    sect5
sect4
  sect5
    [sect6]
No TOC

Using toc.max.depth, you will notice that if a TOC exists, then it has the same number of levels as every other TOC (if the content is there). This table assumes that the other parameter, toc.section.depth, has a high enough value to not interfere with the selection of levels. If it is not changed from its default value of 2, then none of these examples would show titles beyond sect2.

Keeping selected titles out of the toc

There may be situations where you want to exclude certain titles from the table of contents. This may be because they are of minor importance, or perhaps they are meant to be only accessed using an online help system. You can assign a role attribute to such elements, and then add a small template to your customization layer. For example, you might use the attribute value NotInToc to designate elements that should not be in the TOC. The following template would work.

<xsl:template match="sect1[@role = 'NotInToc']"  mode="toc" />

Normally an element's title appears in the toc because the element is processed with a template in mode="toc" to generate the title. In this customization, the template is empty, which means it does nothing. So any element matching it will not appear in the TOC. In this case, it is matching on any sect1 element with the role="NotInToc" attribute. Create similar templates for other elements you might want to exclude.

Caution

If you use profiling using the role attribute, you must include NotInToc in your selected values. If you don't, then those elements with that attribute value will not appear in your output at all because they will be excluded in the profiling step. This is another reason why it is not a good idea to use the role attribute for profiling.

Customizing TOC presentation

If you need to further customize how TOCs are presented, you may need to modify some of the XSL templates. Here is an example of adding the word "Appendix" to appendix entries in the HTML table of contents (which by default just shows the appendix letter).

For print output, you can customize the template named toc.line which can be found in fo/autotoc.xsl. See the section “Styling print TOC entries” for details. For HTML output, there is little opportunity to customize individual lines in the TOC in versions 1.61 and earlier of the DocBook XSL stylesheets. Starting with version 1.62, the HTML stylesheets also implement a toc.line template that can be customized in a manner similar to that for print output.

For HTML processing in versions 1.61 and earlier, the toc lists are generated using the subtoc template in html/autotoc.xsl. The template is used recursively to get nesting, but it doesn't vary per element type. The following lines from subtoc show the problem:

  <xsl:element name="{$toc.listitem.type}">
    <xsl:variable name="label">
      <xsl:apply-templates select="." mode="label.markup"/>
    </xsl:variable>
    <xsl:copy-of select="$label"/>

The first line starts a dt element (in html output) and the rest output the appendix number (called a label in the stylesheets). If you want the word Appendix included, then it has to be inserted between them. Something like the following modified version:

<xsl:element name="{$toc.listitem.type}">
  <xsl:if test="self::appendix">
     <xsl:call-template name="gentext">
       <xsl:with-param name="key" select="'Appendix'"/>
     </xsl:call-template>
     <xsl:text> </xsl:text>
  </xsl:if>
    <xsl:variable name="label">
      <xsl:apply-templates select="." mode="label.markup"/>
    </xsl:variable>
    <xsl:copy-of select="$label"/>

The added test checks for the element name appendix, and then calls the gentext template with its key parameter set to the string Appendix to get the uppercase name for the element in the appropriate language. Then it adds a space after the word to separate it from the appendix letter that follows. Unfortunately, to get this in there you have to copy the entire subtoc template to your customization layer. If a later release of the stylesheets changes that template, you may need to update your customization.