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.

There are three levels of customizing the generated text for empty cross references:

The xrefstyle attribute became available in version 4.3 of the DocBook DTD. If you are using an earlier version of the DTD, then you could use the role attribute instead (see the section “Using role instead of xrefstyle”).

Customizing with an xrefstyle attribute

Version 4.3 of the DocBook DTD made available an xrefstyle attribute to the xref, link, and olink elements to allow an author to indicate special handling for a single cross reference. Note that for a link element, an xrefstyle attribute is limited to controlling the generated page reference, if any. For an olink with text content, then xrefstyle currently has no effect at all on the output.

The DTD does not specify standard values for the xrefstyle attribute, so stylesheets are free to implement whatever scheme they want. The DocBook XSL stylesheets provide three ways to use the xrefstyle attribute:

  • If the attribute value begins with template: then the rest of the text after the colon is taken to be a gentext template to use for that reference.

  • If the attribute value begins with select: then the author can specify components to make up the generated text using key words defined by the stylesheet.

  • Otherwise the attribute value is taken to be a named cross reference style that is defined in the stylesheet's collection of gentext templates.

Each of these methods is described in more detail in the following sections.

Using "template:"

Text that is generated for cross references comes from gentext templates, in which some of the text is fixed and some is filled in from the title or number of the item being referenced. The stock gentext templates reside in the locale files found in the common subdirectory of the stylesheet distribution, such as common/en.xml for English text. Those templates are described in the section “Modifying gentext templates”.

If an xrefstyle attribute starts with the literal string template: then whatever text appears after the colon is taken to be the gentext template for that reference. This option lets you mix any text with a number label and/or title for the cross reference. The following is an example.

Input:
See <xref linkend="UsingMouse" 
      xrefstyle="template:the chapter numbered %n"/>
for more information.

HTML output:
See <a href="#UsingMouse">the chapter numbered 3</a>
for more information.

The highlighted text is used as the gentext template. The %n is replaced by the chapter number during processing. You could use %t if you want to include the chapter title in a gentext template. Since the text is entered as an attribute value, you cannot include DocBook tags with it. You can include text entities, though. Keep in mind that if the document is translated to other languages, then any regular words in the attribute will have be translated too. Normally translators would not look in attribute values for words to translate.

Using "select:"

A somewhat more structured customization is available when you start an xrefstyle attribute with the literal string select:. This option lets you choose the components that make up the generated text. You specify one or more keywords that are defined in the stylesheet, and the stylesheet then assembles a temporary gentext template for that reference. For example:

Input:
<xref linkend="MouseButtons" 
      xrefstyle="select: labelnumber quotedtitle"/>

HTML output:
<a href="#MouseButtons">2.1: "Using Mouse Buttons"</a>

The stylesheet constructs a gentext template based on the keywords labelnumber and quotedtitle. In this scheme, there are three possible components to the generated text, and each has several possible keywords. This table summarizes the keywords.

Table 15.1. Keywords for xrefstyle select:

ComponentKeywordExampleDescription
number labellabelTable 3Complete label name and number
labelnameTableJust the label name
labelnumber3Just the label number
titletitleUsing a MouseTitle without quotes
quotedtitle"Using a Mouse"Title in quotes
page numberunspecified[12]Stock page citation for all xref elements when the insert.xref.page.number parameter is set to yes, and for all link elements when the insert.link.page.number parameter is set to yes.
page(page 12)Page number in parentheses
PagePage 12Capitalized page label
pageabbrev(p. 12)Abbreviated label in parentheses
pagenumber12Just the page number
nopage Turn off the page number for this xref element when the insert.xref.page.number parameter is set to yes, or for this link element when the insert.link.page.number parameter is set to yes.
document namedocnamein Reference Manual(Olinks only). Adds the title of the other document being referenced by an olink.
docnamelongin the document named Reference Manual(Olinks only). Adds a longer version of a title referenced by an olink.
nodocname (Olinks only). Turn off the document name when the olink.doctitle parameter is set to yes.

Note these features:

  • You can specify zero or one keyword for each component type. If a component does not have a keyword, then it is omitted from the output.

  • Although the keywords can be specified in any order, the presentation order in the output is always label, title, and page.

  • Page numbers are generated only for print output, not HTML output.

  • The overall control of page references in print output is set by the insert.xref.page.number stylesheet parameter for xref elements, and by insert.link.page.number for link elements. Each has three possible values:

    no

    Page number references are not included in the output. This is the default value, so you must reset this parameter to get any page cross references in your print output.

    yes

    Page number references are included for each xref or link instance. If the style is not specified with an xrefstyle attribute, then the stock page citation style is used (see the table above).

    maybe

    A page number reference is output only for each xref of link with a page component in its xrefstyle attribute.

  • If you want page references on most of your xref elements, then set insert.xref.page.number to yes and turn off individual instances with a nopage keyword in its xrefstyle attribute. If you want page references on only a few xref elements, then set insert.xref.page.number to maybe and add an xrefstyle attribute with a page component to those few instances. Likewise you can control page references on link elements by using the insert.link.page.number parameter in a similar fashion.

  • If you want to globally change the default page citation style from [12] to something else, then customize the page.citation gentext entry (see the section “Customizing generated text” for details on customizing gentext entries). The following example changes the default style to (p. 12):

    <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="page.citation" text=" (p. %p)"/>
        </l:context>
      </l:l10n>
    </l:i18n>
    

    The %p is the placeholder for the generated page number. If you are translating your documents to other languages, you may need to add similar customizations to the gentext for those languages.

  • The whitespace and punctuation that is inserted between components in the output is specified by these stylesheet parameters:

    xref.label-title.separator

    Used between label and title, if both are specified. Default value is a colon and blank space.

    xref.title-page.separator

    Used between title and page number, if both are specified. Default value is a blank space.

    xref.label-page.separator

    Used between label and page number, if both are specified and a title is not. Default value is a blank space.

  • The label name and quoting characters are taken from the locale files in the common subdirectory of the distribution, so they are appropriate for each language that DocBook supports.

This method is useful when you need a small variation on the standard generated text for a cross reference. It is less raw and more consistent than the ad hoc gentext template used in the template: method for xrefstyle.

Using a named xrefstyle

The two previous methods do not require a stylesheet customization to use them. If you are willing to create and use a stylesheet customization layer, then you can add any number of named gentext templates for cross references to particular target elements. Then you can call such gentext templates by specifying one of the names in an xrefstyle attribute value.

The following example adds a style named num-qt (number and quoted title) for sect1 references.

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-number-and-title">
      <l:template name="sect1" style="num-qt" text="%n-&#8220;%t&#8221;"/>
    </l:context>
  </l:l10n>
</l:i18n>

Input:
<xref linkend="MouseButtons" xrefstyle="num-qt"/>

HTML output:
<a href="#MouseButtons">2.1-"Using Mouse Buttons"</a>

Note these features:

  • The customization layer uses the method described in the section “Customizing generated text” to add a new gentext template.

  • The new gentext template is similar to the others, but it adds a style="num-qt" attribute to identify the named style.

  • This gentext template applies only to the element identified by the name attribute, which is sect1 in this case. To use this style on other elements you must add a similar gentext template for each element. They can share the same style name.

  • Each gentext template is contained within a language and a context. It will only be used if called on that target element in the same language and context. Keep in mind that there are several possible contexts for xref gentext templates (see the section “Modifying gentext templates”). In this case, if section numbering is not turned on by the section.autolabel stylesheet parameter, then the xref-number-and-title context is not in effect and this template will not be used. You may need to add more gentext templates for a named style in other xref contexts.

This method of customizing xref generated text is most useful when you want a set of standardized styles, and you are willing to invest the time to create the new templates in a customization layer.

Customizing page citations

The print stylesheet provides several options for customizing page references generated by xref elements.

  • You can enable or disable xref page references for the whole document using the insert.xref.page.number parameter, as described in the section “Using "select:"”.

  • If you want to change the default page reference style that uses square brackets, you can customize the gentext template named page.citation, which is in the xref context in the collection of gentext templates. See the section “Modifying gentext templates” for a description of the general process.

  • You can select a particular page reference style for an individual xref in your document by adding an xrefstyle attribute to it, as described in the section “Using "select:"”.

  • If you want to customize the page reference styles that are selected by xrefstyle, then you can customize the gentext templates named page, Page, and pageabbrev. They are also in the xref context in the collection of gentext templates. See the section “Modifying gentext templates” for a description of the general process.

Controlling page citations by element

If you want to style (or turn off) page references for particular elements, you can add custom templates using mode="page.citation" to your customization layer. If you look in fo/xref.xsl, you will find that in the template with match="xref", each page citation is generated using this line:

<xsl:apply-templates select="$target" mode="page.citation">

By default, there is one match="*" template in that mode:

<xsl:template match="*" mode="page.citation">
  <xsl:param name="id" select="'???'"/>

  <fo:basic-link internal-destination="{$id}"
                 xsl:use-attribute-sets="xref.properties">
    <fo:inline keep-together.within-line="always">
      <xsl:call-template name="substitute-markup">
        <xsl:with-param name="template">
          <xsl:call-template name="gentext.template">
            <xsl:with-param name="name" select="'page.citation'"/>
            <xsl:with-param name="context" select="'xref'"/>
          </xsl:call-template>
        </xsl:with-param>
      </xsl:call-template>
    </fo:inline>
  </fo:basic-link>
</xsl:template>

This template generates the page reference using the name="page.citation" gentext element from the current language's locale file. Since this mechanism uses a mode, you can add templates using that mode that match on particular elements to change the behavior for those elements. For example, you might want to turn off page references to chapters or appendixes, since they are easy to find because they are numbered.

<xsl:apply-templates select="chapter|appendix" mode="page.citation"/>

This empty template will turn off page references for chapters and appendixes, and leave the default template to handle all other target elements.

Using role instead of xrefstyle

The xrefstyle attribute was introduced in version 4.3 of the DocBook DTD. If you are using an earlier version of the DTD, then you can use the role attribute instead. When the stylesheet parameter use.role.as.xrefstyle parameter is set to 1 (the default value), then a role attribute on an xref element is treated as if it were an xrefstyle attribute. This means you do not have to upgrade your documents to use DocBook 4.3 or later to use the stylesheet features for customizing cross reference text.

Modifying gentext templates

You customize cross reference text by modifying gentext strings for your locale in your customization layer. See the section “Generated text” for a general description of customizing generated text. For cross references, you want to look for gentext templates in one of the xref contexts in the language file you are working with, such as common/en.xml. These are the xref contexts (as of version 1.62 of the stylesheets) and when they apply:

ContextGenerates:Applies to:
context="xref"The element's title.Cross references to elements that are not numbered. Includes chapters when the parameter chapter.autolabel is set to zero. Same with appendix, part, preface, and section elements and their respective parameters.
context="xref-number"The element's number label, such as Chapter 3.Cross references to elements that are numbered, such as chapter, appendix, figure, table. Also applies to sections when they are numbered. Used when the stylesheet parameter xref.with.number.and.title is set to zero.
context="xref-number-and-title"The element's number label and title.Cross references to elements that are numbered, such as chapter, appendix, figure, table. Also applies to sections when they are numbered. Used when the stylesheet parameter xref.with.number.and.title is set to 1 (default).

For example, the common/en.xml file includes the following gentext templates. The text for chapter is highlighted in each context.

<l:context name="xref">
   <l:template name="abstract" text="%t"/>
   <l:template name="appendix" text="%t"/>
   <l:template name="chapter" text="%t"/>
   ...
</l:context>
<l:context name="xref-number">
   <l:template name="appendix" text="Appendix&#160;%n"/>
   <l:template name="chapter" text="Chapter&#160;%n"/> (&#160; is a non-breaking space)
   ...
</l:context>
<l:context name="xref-number-and-title">
   <l:template name="appendix" text="Appendix&#160;%n, %t"/>
   <l:template name="chapter" text="Chapter&#160;%n, %t"/>
   ...
</l:context>
   ...

Each DocBook element that can generate text has a l:template element within each context that can apply. 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).

For example, an xref that points to a chapter would normally generate text like Chapter 3, Using a Mouse (the non-breaking space was replaced for clarity). The context="xref-number-and-title" template is used because chapters are numbered and the stylesheet parameter xref.with.number.and.title is set to 1 by default. If you set xref.with.number.and.title to zero, then the context="xref-number" template is used instead. If you set chapter.autolabel to zero to turn off chapter numbering, then the context="xref" template is used.

To customize cross references, you add new gentext templates to your customization layer that override the stock templates. You have to make sure you cover all the targets elements you reference, and in all the contexts that you use.

For example, if you prefer to use a 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-number-and-title"> 
      <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-number-and-title"> 
      <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-number-and-title"> 
      <l:template name="appendix" text="Annexe %n: &#171;%t&#187;"/> 
      <l:template name="chapter" text="Chapitre %n: &#171;%t&#187;"/> 
    </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 them as separate modification files.

Customizing cross reference behavior

The mechanism of using gentext templates to generate cross references has one big limitation. The generated text is specified using an attribute in a l:template element in a localization file. An attribute value cannot contain element markup, nor can it alter the cross reference behavior under different contexts. If you need more control over how a cross reference is generated, you can create or customize a template in mode="xref-to".

If you look in the DocBook XSL stylesheet file xref.xsl (for either HTML or FO), you will see that the cross reference text is generated with this line:

<xsl:apply-templates select="$target" mode="xref-to">

The $target variable contains the element being referenced. Since this is a mode, there can be separate templates matching on each element type. You can customize the behavior for individual elements by creating or customizing a template that matches on that element in this mode.

If you examine the templates with mode="xref-to" in xref.xsl, you will see that most of them use xsl:apply-templates in mode="object.xref.markup". That mode is the DocBook mechanism that selects the appropriate gentext template from the localization files, and fills in the title and number for a cross reference. For example, here is the gentext template for sections when section numbering is not turned on:

<l:context name="xref">
  ...
  <l:template name="section" text="the section called &#8220;%t&#8221;"/>
  ...

Some templates using mode="xref-to" do not use the gentext template mechanism. For example:

<xsl:template match="author|editor|othercredit|personname" mode="xref-to">
  <xsl:param name="referrer"/>
  <xsl:param name="xrefstyle"/>

  <xsl:call-template name="person.name"/>
</xsl:template>

If you want to customize the behavior or generate additional markup for a cross reference for a particular element, then add a template that matches on that element and uses that mode. For example, you could customize how an author is referenced so that their affiliation is added:

<xsl:template match="author" mode="xref-to">
  <xsl:param name="referrer"/>
  <xsl:param name="xrefstyle"/>

  <xsl:call-template name="person.name"/>
  <xsl:if test="child::affiliation">
    <xsl:text> (</xsl:text>
    <xsl:apply-templates select="affiliation"/>
    </xsl:text>)</xsl:text>
  </xsl:if>
</xsl:template>

This template for author elements checks to see if it contains an affiliation element, and if so, outputs it within parentheses after the name. This template does not affect cross references to editor or other name elements.

Customizing cross reference typography

Perhaps you want to change the typographical style for the generated text of a cross reference. For example, you might notice that xrefs to chapters italicize the chapter title, but xrefs to sections do not. You might think the gentext templates would let you customize the style, but they do not. The gentext templates specify text in attributes, and attributes are not permitted to have elements in XML. So you cannot wrap the gentext in HTML or FO elements for formatting.

You can italicize section titles with a stylesheet customization using the insert.title.markup mode. That mode is used to generate the title to replace the %t placeholder in a gentext template. For FO output, you need to create a template like the following in your customization layer:

<xsl:template  match="sect1|sect2|sect3|sect4|sect5|section"  
               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 a section title, but only if the purpose of the title is an xref. That way you do not also italicize these titles in their original location or the table of contents.

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.

If you want to style all cross references in FO output, for xref, link, and ulink references, then a simpler mechanism is available. The xref.properties attribute-set can be used to add FO properties to the text of all such cross references. For example, if you want the cross reference text to appear in blue for ulink elements, then use this customization:

<xsl:attribute-set name="xref.properties">
  <xsl:attribute name="color">
    <xsl:choose>
      <xsl:when test="self::ulink">blue</xsl:when>
      <xsl:otherwise>inherit</xsl:otherwise>
    </xsl:choose>
  </xsl:attribute>
</xsl:attribute-set>

This sets the color property conditionally. When the element using the xref.properties attribute set is a ulink, then the test matches and the color is blue. Otherwise the color is inherited, so there is no color change. Be sure to include the otherwise part. If you want all three cross reference elements to be blue, then you can just set the attribute value without using the choose statement.

For olink elements, the olink.properties attribute-set is available instead. It sets properties on the text generated for olink elements. See Chapter 24, Olinking between documents for more information.

To style all cross references in HTML output, just create a CSS selector on the A element, which is used for all hot links in HTML.