Chapter 9. General customizations

Table of Contents

Custom section numbering
Tables of contents (TOC)
Components showing a TOC
Turning on section TOCs
Levels in a TOC
Customizing toc presentation
Keeping selected titles out of the toc
Customizing cross references
Customizing cross reference style

Many customizations can be applied to both HTML and FO (print) output because the stylesheets share some code and processing styles.

Custom section numbering

As described in the section called “Chapter and section numbering”, you can turn on standard section numbering with stylesheet parameters. But you may want to further refine the numbering style.

For example, you may want to number sections only up to a certain section depth. If your document has a lot of deeply nested small subsections, then the numbers can get long and intrusive. But there is no parameter that controls the depth of section numbering.

Fortunately, you don't need to replace any templates to make this change. You can achieve the effect by modifying some gentext templates. Add something like this to your customization layer:

<xsl:param name="section.autolabel" select="1"/>
<xsl:param name="toc.section.depth" select="2"/>
<xsl:param name="section.label.includes.component.label" select="1"/>

<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:context name="title-numbered">
      <l:template name="sect3" text="%t"/>
      <l:template name="sect4" text="%t"/>
      <l:template name="sect5" text="%t"/>
    </l:context>

    <l:context name="section-xref-numbered">
      <l:template name="sect3" text="the section called “%t”"/>
      <l:template name="sect4" text="the section called “%t”"/>
      <l:template name="sect5" text="the section called “%t”"/>
    </l:context>

  </l:l10n>
</l:i18n>

The first parameter turns on section numbering, and the second one limits the TOC list to the level of sect2 at the most. The third parameter adds the chapter number to the numbering (the usual case for multiple chapter numbering).

The <l:i18n> stuff customizes the gentext templates, in this case for English. You'll have to do something similar for other languages if you use them. It redefines how the section titles and cross references are generated for sect3 through sect5 when in the 'sections being numbered' context. In this case, although sections are being numbered, you want these section levels to just display %t (title) and not %n (number). See the section called “Customizing generated text” for further explanation of the gentext elements.

It is generally easiest if you can meet your customization needs by putting modified gentext strings in your customization layer. That will handle placement of the number relative to any generated words, as well as punctuation. If you want to go even further in customizing the numbering of sections, you'll probably need to rewrite some templates.

The %n variable in the gentext strings is processed using the label.markup mode. That is, the element needing the number is processed with:

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

The XSL processor finds the template with mode="label.markup" that best matches the current element. The templates with this mode are in the stylesheet file common/labels.xsl for all the elements that might get numbered. They are in common so the same templates can be used for both HTML and FO output. Templates with mode label.markup return just the number. The same templates are used to generate the numbers that appear in any tables of contents.

Section labelling such as 2.1.4 uses several of the templates, because the number is assembled from ancestor elements as well as the current element. Those templates apply templates on their parent element, selected as ".." in the template.

Tables of contents (TOC)

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

Components showing 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. Although it 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 book element will also generate tables of figures, tables, examples, and equations. The word title triggers printing the title of 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.

You can control which elements have these 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:

<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. You can even set this simple value on the command line:

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

Because the list uses whitespace 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.

Turning on section TOCs

Which section levels have a TOC is controlled by two parameters. You will notice that the default value of the generate.toc parameter described above 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 section TOC output.

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, and their equivalents in nested section elements.

This arrangement lets you establish a style for which TOCs could appear at various section levels by modifying the big generate.toc parameter in your customization layer. Then you can select the actual output level at runtime with the single generate.section.toc.level parameter. Both parameters must enable a section level for its TOC to appear.

Levels in a TOC

In addition to controlling which section levels have a TOC list at their beginning, you can control how many nested levels of headings a TOC list should have. Use the toc.section.depth parameter to indicate which 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.

This parameter is a limiting value that applies to all TOCs. Using the default value of 2, a book TOC would include titles for chapter, sect1, and sect2, while a sect1 TOC would include titles for only sect2. It currently isn't possible to adjust the limit for the different TOCs.

A couple of example can illustrate how the two TOC parameters work together. Say you want only book and chapter TOCs, and they should include up to sect4 levels. The book and chapter TOCs are turned on by the generate.toc parameter. To avoid section TOCs, leave generate.section.toc.level set to zero (the default). Then set toc.section.depth to 4.

Another example might be chunked HTML output, where each sect1 is chunked into a new file, and you want to show a TOC at the top of each chunked file. Perhaps it is your style to only list the highest headings within those chunked files, which would be sect2. Those requirements would be met by settting generate.section.toc.level to 1 and toc.section.depth to 2.

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).

There is little opportunity to customize individual lines in the TOC for HTML output. For FO output, you can customize the template named toc.line which can be found in fo/autotoc.xsl. See the section called “Styling print TOC entries” for details.

For HTML processing, 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. These 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, then it has to be inserted between them. Something like this modified version:

  <xsl:element name="{$toc.listitem.type}">
  <xsl:if test="local-name(.) = 'appendix'">
     <xsl:call-template name="gentext" key="Appendix"/>
     <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 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.

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" />

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.

Customizing cross references

DocBook has two kinds of cross references: those that are empty and those that provide their own text. The empty cross reference elements (xref and empty olink) have their text generated by the stylesheets. The generated text can be customized.

You customize cross reference text by modifying gentext strings in your customization layer. See the section called “Generated text” for a general description of customizing generated text. For cross references, you want to look for the context="xref" set of gentext templates in the language files you are working with. For example, the file common/en.xml includes the following:

<l:context name="xref">
   <l:template name="abstract" text="%t"/>
   <l:template name="answer" text="A: %n"/>
   <l:template name="appendix" text="Appendix %n"/>
   ...

Each DocBook element that can generate text has its own l:template element. The text attribute value is used to generate the output for a cross reference to that element. The %t placeholder resolves to the target element's title, and %n resolves to its number (if it is numbered). So an xref whose linkend attribute points to an appendix will generate the text Appendix A, or whatever the appendix number is.

If you prefer to include the title with colon and quotes in cross references to chapters and appendixes, you can add the following to your customization layer:

<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:context name="xref"> 
      <l:template name="appendix" text="Appendix %n: &#8220;%t&#8221;"/> 
      <l:template name="chapter" text="Chapter %n: &#8220;%t&#8221;"/> 
    </l:context>    
  </l:l10n>
</l:i18n>

If you want to do this for French as well as English, you'll need the following:

<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:context name="xref"> 
      <l:template name="appendix" text="Appendix %n: &#8220;%t&#8221;"/> 
      <l:template name="chapter" text="Chapter %n: &#8220;%t&#8221;"/> 
    </l:context>    
  </l:l10n>
  <l:l10n language="fr"> 
    <l:context name="xref"> 
      <l:template name="appendix" text="Annexe %n: &#8220;%t&#8221;"/> 
      <l:template name="chapter" text="Chapitre %n: &#8220;%t&#8221;"/> 
    </l:context>    
  </l:l10n>
</l:i18n>

The gentext templates are shared by the HTML and FO stylesheets. If you are satisfied that your changes work in both output formats, you can put all of your gentext changes in a separate file and bring them into each of your stylesheet customization layers using:

<xsl:param name="local.l10n.xml" select="document('mygentextmods.xml')"/>

Or if you find you need different cross reference styles for the different output formats, you can keep maintain them as separate modifications.

Customizing cross reference style

Perhaps you want to change the style for the generated text of a cross reference. For example, you might want references to figures, tables, and examples to be in italic. You can accomplish this with a stylesheet customization. For FO output, you need to create this template in your customization layer:

<xsl:template match="figure|table|example|equation" mode="insert.title.markup">
  <xsl:param name="purpose"/>
  <xsl:param name="xrefstyle"/>
  <xsl:param name="title"/>

  <xsl:choose>
    <xsl:when test="$purpose = 'xref'">
      <fo:inline font-style="italic">
        <xsl:copy-of select="$title"/>
      </fo:inline>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy-of select="$title"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

The mode named insert.title.markup is designed to handle adding markup to titles in a given context. The template parameter named purpose indicates the context. In this case, you want to wrap an inline font-style tag around the xref title, but only if the purpose of the title is an xref. That way you don't also italicize these titles in their original location.

If you want something similar for HTML output, just copy this template to your HTML customization layer and replace the fo:inline start and end tags with the equivalent HTML I start and end tags.