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 others require a customization layer.
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 do not 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.
do not 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.
do not 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.
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”.
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 10.1. How toc.section.depth affects book and chapter TOCs
toc.section.depth | Book 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 10.2. How toc.max.depth affects book and chapter TOCs (HTML output only)
toc.max.depth | Book TOC includes: | Chapter TOC includes: |
---|---|---|
0 | No TOC | No 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.
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.
If you process a group of books inside a set
element, then the set can have a table of contents too. Normally it would be a complete table of contents, listing the books, chapters, and sections to whatever level was specified for books.
You might not need such detail in a set TOC, since each book TOC has those details. If you want your set TOC to list just the book titles, then you can customize a template. The template is different if you are doing print or HTML output.
For print output, you would customize the template with match="book|setindex" mode="toc"
from the stylesheet module fo/autotoc.xsl
. After calling the template named toc.line
to format the book title, the template selects the child nodes to process under it. Since this template is only called by the set.toc
template, you can reduce it to formatting just its own title.
<xsl:template match="book|setindex" mode="toc"> <xsl:param name="toc-context" select="."/> <xsl:call-template name="toc.line"/> </xsl:template>
For HTML output, the set.toc
template processes each book
element in mode="toc"
. Normally that template calls the subtoc
template with a parameter named nodes
that selects the book's child elements. Instead, select an empty node set by selecting a non-element name, such as EMPTY
(since DocBook has no element of that name).
<xsl:template match="book" mode="toc"> <xsl:param name="toc-context" select="."/> <xsl:call-template name="subtoc"> <xsl:with-param name="toc-context" select="$toc-context"/> <xsl:with-param name="nodes" select="EMPTY"/> </xsl:call-template> </xsl:template>
The subtoc
template generates the book
title, and then stops because it has no child nodes to process. This change will not affect the book's own TOC because it does not use this template, instead calling division.toc
.
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 10.3. Section TOCs with toc.section.depth
generate.section.toc.level | toc.section.depth | sect1 TOC includes: | sect2 TOC includes: | sect3 TOC includes: | sect4 TOC includes: |
---|---|---|---|---|---|
1 | 2 |
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 | |
2 | 2 |
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 | |
3 | 2 |
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 10.4. Section TOCs with toc.max.depth (HTML only)
generate.section.toc.level | toc.max.depth | sect1 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 | |
2 | 1 |
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 | |
3 | 1 |
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
.
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.
If you use profiling using the role
attribute, you must include NotInToc
in your selected values. If you do not, 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.
Some document designs require that certain extra elements be added to the document's table of contents. Some candidate elements include refentry
, article
(mixed in with chapters), procedure
(those with titles), block elements like sidebar
or titled lists, or certain of the formal elements like table
, figure
, or example
. For instance, you might customize example
elements to contain formal exercises, and want to list those along with section titles in the TOC.
Adding an element to a TOC is generally a two-step process in DocBook XSL:
Add the new element to the templates that select TOC elements.
Add a template for the new element in mode="toc"
to generate its entry.
To understand how to customize, it helps to know the sequence of processing for a table of contents. All of the these templates that generate a TOC are in the stylesheet files named autotoc.xsl
(for both HTML and FO).
Template sequence for a TOC
Before a TOC is started, the stylesheet parameter generate.toc
is checked to see if it has an entry for the current element. If not, then there will be no TOC started at that element level. See the section “Which components have a TOC” for information on that parameter.
If the generate.toc
parameter also has a title
entry for the current element, then a template is called to generate the title in the current language.
A TOC list starts with a call to one of the top-level templates such as set.toc
, division.toc
(for book or part), component.toc
(for chapter, appendix, article), or section.toc
.
The top-level TOC template selects the child elements that should be included in the TOC. Note that a book TOC does not include the title of the book itself, only the child elements of book. Likewise for the other top-level templates. It is this selection process that must be customized to include a new element.
The top-level template then processes the set of child nodes. In FO, the selected nodes have templates applied in mode="toc"
. In HTML, the selected nodes are passed as a parameter to a template named make.toc
to process them in mode="toc"
.
The mode="toc"
template for the selected child calls toc.line
to format its title. It then selects its children in turn, and processes them in mode="toc"
to produce nested entries. In this way the stylesheet descends through the entire document hierarchy. Note that in HTML, the subtoc
template is called to apply templates in mode="toc"
in order to add the proper HTML wrapper elements to indent the sub entries.
For instance, if you want to add sidebar
elements to a book TOC, you first have to customize where to select them for the TOC. Since a sidebar
cannot appear as a direct child of book
, you do not need to customize the division.toc
template that starts the TOC. But you will need to customize these two templates to include sidebar
, as shown in these two code snippets. Since a title
element is optional in sidebar
, these select only those sidbar
elements that contain a title
.
Add sidebar under chapter: <xsl:template match="preface|chapter|appendix|article" mode="toc"> ... <xsl:call-template name="toc.line"/> <xsl:variable name="nodes" select="section|sect1|sidebar[title] |simplesect[$simplesect.in.toc != 0] |refentry|appendix"/> Add sidbar under section: <xsl:template match="section" mode="toc"> ... <xsl:if test="$toc.section.depth >= $depth"> <xsl:call-template name="toc.line"/> <xsl:if test="$toc.section.depth > $depth and $toc.max.depth > $depth.from.context and (section or sidebar)"> <fo:block id="toc.{$cid}.{$id}"> <xsl:attribute name="margin-left"> <xsl:call-template name="set.toc.indent"> <xsl:with-param name="reldepth" select="$reldepth"/> </xsl:call-template> </xsl:attribute> <xsl:apply-templates select="section|sidebar[title]" mode="toc"> <xsl:with-param name="toc-context" select="$toc-context"/> </xsl:apply-templates>
The second step is to add a template matching on sidebar
in mode="toc"
, since one does not already exist in the stylesheet.
<xsl:template match="sidebar" mode="toc">
<xsl:call-template name="toc.line"/>
</xsl:template>
This template just calls the toc.line
template to process the title, and does not try to add any children of sidebar
to the TOC.
If you need to further customize how TOCs are presented, you may need to modify some of the XSL templates. The following is an example of adding the word "Appendix" to appendix
entries in the print table of contents (which by default just shows the appendix letter).
<xsl:template name="toc.line"> <xsl:param name="toc-context" select="NOTANODE"/> <xsl:variable name="id"> <xsl:call-template name="object.id"/> </xsl:variable> <xsl:variable name="label"> <xsl:choose> <xsl:when test="self::appendix"> <xsl:call-template name="gentext"> <xsl:with-param name="key">appendix</xsl:with-param> </xsl:call-template> <xsl:text> </xsl:text> <xsl:apply-templates select="." mode="label.markup"/> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="." mode="label.markup"/> </xsl:otherwise> </xsl:choose> </xsl:variable> ... rest of toc.line template
For print output, you can customize this template named toc.line
which can be found in fo/autotoc.xsl
. See the section “Styling print TOC entries” for a detailed example. For HTML output, the stylesheets also implement a toc.line
template in html/autotoc.xsl
that can be customized in a manner similar to that for print output.
Both versions of the toc.line
template include a passed-in template parameter named toc-context
. That parameter references the element that contains the TOC list. So if a book TOC is being generated, for example, that parameter references the book
element. You can change the TOC presentation based on the toc-context
parameter. In this example, the label number is printed in bold when the TOC is not at the book level:
<xsl:template name="toc.line">
<xsl:param name="toc-context" select="NOTANODE"/>
<xsl:variable name="id">
<xsl:call-template name="object.id"/>
</xsl:variable>
<xsl:variable name="label">
<xsl:choose>
<xsl:when test="$toc-context/self::book">
<xsl:apply-templates select="." mode="label.markup"/>
</xsl:when>
<xsl:otherwise>
<fo:inline font-weight="bold">
<xsl:apply-templates select="." mode="label.markup"/>
</fo:inline>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
...
Since the toc-context
template parameter contains a node, not a string, it can be used in an XPath statement that tests if it is a book
element. If it is, then it just generates the label number, otherwise it wraps the label number in an fo:inline
to add the bold property.
DocBook XSL: The Complete Guide - 4th Edition | PDF version available | Copyright © 2002-2007 Sagehill Enterprises |