Customizing DocBook 5 XSL

Customizing the DocBook 5 stylesheets is almost identical to customizing the original DocBook 4 stylesheets. The main difference is the namespace.

A DocBook 5 customization must:

Example 9.4 is a short customization example.

Example 9.4. DocBook 5 customization

<?xml version="1.0"?>
<xsl:stylesheet 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:fo="http://www.w3.org/1999/XSL/Format"
     xmlns:d="http://docbook.org/ns/docbook" 1
     exclude-result-prefixes="d" 2
     version="1.0">

<xsl:import href="docbook-xsl-ns/fo/docbook.xsl"/>  3

<xsl:param name="double.sided">1</xsl:param>
...
<xsl:template mode="vl.as.list" match="d:varlistentry"> 4
  <xsl:variable name="id"><xsl:call-template name="object.id"/></xsl:variable>
  <fo:list-item id="{$id}" xsl:use-attribute-sets="list.item.spacing">
    <fo:list-item-label end-indent="label-end()" text-align="start">
      <fo:block>
        <xsl:apply-templates select="d:term"/>  5
      </fo:block>
    </fo:list-item-label>
    <fo:list-item-body start-indent="body-start()">
      <fo:block>
        <xsl:apply-templates select="d:listitem"/> 5
      </fo:block>
    </fo:list-item-body>
  </fo:list-item>
</xsl:template>

1

Declare the DocBook namespace and include a prefix, which here is d:. You can use any prefix in your stylesheet as long as you declare it like this.

2

Tell the processor to not add the DocBook namespace declaration in the output. This has no effect except to omit a namespace declaration that is never used in the output content, keeping it a bit cleaner. If you accidentally write a DocBook element to the output (using, say, xsl:copy), then the processor will override this instruction and add the namespace declaration anyway.

3

Import the base stylesheet from the DocBook 5 XSL stylesheet distribution.

4

Add the prefix to any DocBook element names in match attributes.

5

Add the prefix to any DocBook element names in XPath expressions.


A more useful DocBook 5 customization is described in the section “Annotations customization”.

DocBook 5 customization details

There are a few differences you will need to remember of when customizing DocBook 5 instead of DocBook 4 stylesheets. These include:

  • Be sure to add the namespace prefix to all DocBook element names in your stylesheet. They can be found in any of the following XSL attributes:

    match      select
    test       count
    from       use
    elements
    

    If you have element names in any general entities that you declare and use in your stylesheet, then those must also get a prefix.

  • In DocBook 5, the id attribute is replaced with the xml:id attribute. Although it has a namespace prefix, you do not need to declare it because it is a standard prefix in XML.

  • In DocBook 5, the lang attribute is replaced with the xml:lang attribute.

  • In DocBook 4, you could use the XSL name() function to test an element's name. That only worked because DocBook 4 did not use a namespace. The name() function normally returns the namespace prefix and local name for an element. In a DocBook 5 stylesheet, you should use the local-name() function if you just want the element name without its prefix.

  • In DocBook 5, the metadata container for all elements is named info. If you want to match on perhaps a title of an element, you may need to look in its info element.

  • If your stylesheet is divided into several modular files that are combined with xsl:import or xsl:include, be sure that all modules follow these guidelines.

Annotations customization

This section shows how to write a stylesheet customization for DocBook 5. It also shows how the new annotation element might be put to use.

The customization decribed below puts annotations of a certain type into the side margin as floats. The example is kept simple for clarity, so it is not a very robust implementation of annotations. For example, it handles annotations associated only with para elements that are children of chapter or section. This is to avoid conflicting with para elements in footnote and other locations incompatible with side float.

Example 9.5 shows how an annotation element can be entered in a document.

Example 9.5. Annotation usage

<chapter xmlns="http://docbook.org/ns/docbook" version="5.0">
  <title>My chapter title</title>
  <info>
    <annotation annotates="intro" role="instructor.note">
      <para>Show intro slides and wait for questions.</para>
    </annotation>
  </info>
  <para xml:id="intro">This chapter introduces ...
    

Note these features of the usage example:

  • The annotation element is placed in any convenient location, in this case the chapter's info element.

  • The annotation is associated with an element by matching its annotates attribute to an xml:id elsewhere in the document. In this case, the xml:id is on a para element.

  • This annotation has a role attribute that will be used to select it for output.

Example 9.6 shows a stylesheet customization to output this type of annotation.

Example 9.6. Annotation stylesheet customization

<xsl:param name="body.start.indent">40mm</xsl:param> 1
<xsl:param name="show.instructor.notes" select="1"/>

<xsl:template match="d:para[parent::d:section or parent::d:chapter]"> 2
  <fo:block xsl:use-attribute-sets="normal.para.spacing">
    <xsl:call-template name="anchor"/>
    <xsl:call-template name="apply.annotations"/> 
    <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<xsl:template name="apply.annotations">
  <xsl:variable name="id" select="@xml:id"/> 3

  <xsl:for-each select="//d:annotation[@role='instructor.note']"> 4
    <xsl:if test="@annotates = $id"> 5
      <xsl:apply-templates mode="show.annotation" select="."/>
    </xsl:if>
  </xsl:for-each>
</xsl:template>

<xsl:template match="d:annotation[@role = 'instructor.note']"  
              mode="show.annotation"> 6
  <xsl:if test="$show.instructor.notes != 0">
    <xsl:call-template name="floater"> 7
      <xsl:with-param name="position">left</xsl:with-param>
      <xsl:with-param name="width">35mm</xsl:with-param>
      <xsl:with-param name="content">  8
        <fo:block xsl:use-attribute-sets="instructornote">
          <fo:block font-weight="bold">
            <xsl:text>Instructor Note</xsl:text>
          </fo:block>
          <xsl:apply-templates/>
        </fo:block>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

<xsl:attribute-set name="instructornote">  9
  <xsl:attribute name="font-size">8pt</xsl:attribute>
  <xsl:attribute name="line-height">9.5pt</xsl:attribute>
  <xsl:attribute name="text-align">left</xsl:attribute>
  <xsl:attribute name="end-indent">2mm</xsl:attribute>
  <xsl:attribute name="padding">1mm</xsl:attribute>
  <xsl:attribute name="border">0.2pt solid blue</xsl:attribute>
</xsl:attribute-set>

1

Set the body.start.indent parameter to leave sufficient room for the side notes. Add a new parameter that controls whether or not the instructor notes are output.

2

Annotations are not output by default, so in this example the template for para is customized to trigger annotation processing. Note that all DocBook element references have the namespace prefix. The call to the apply.annotations templates is made inside the fo:block for the paragraph so the float is positioned with that block.

3

The context node for apply.annotations is the para element that called it. Save the xml:id value of the current para element in a variable to use for comparison.

4

Look at each annotation element in the entire document that has the right role value. This XPath is not very efficient, so creating and using an xsl:key would speed up such lookups for large documents.

5

Select only those annotation elements whose annotates attribute matches the para ID. This comparison with equals is not robust because an annotates attribute can contain a space-separated list of values.

6

For each selected annotation, process the element in a special mode. If you do not use a mode, then the annotations may accidentally be processed when the elements of the document are processed in document order. In this case the annotation is safe inside the info element, but it could be anywhere.

7

If the parameter to control instructor notes is turn on, create a float by calling the DocBook utility template named floater. That template takes parameters to specify position, width, and content of the float.

8

Into the template's content parameter, process the annotation into a block with an attribute-set to apply properties. You can add a title as shown here as well.

9

The attribute-set is used for these special annotation floats. This example formats the text into a blue border with sufficient spacing around it, and in a smaller font size.