3. Customizing the stylesheets

In many circumstances, the stylesheets can be used “out of the box” without any customization. But sometimes you may need to change the formatting of certain elements. One common reason is to change the formatting of title pages or navigational features. In other cases, it may be to support local extensions to DocBook or simply to change the markup to support a particular use case.

Three approaches are possible, with increasing degrees of effort: changing stylesheet parameters, creating your own customization layer, or making broader changes to the stylesheet’s implementation.

The subject of broader implementation changes is the subject of Chapter 4, Implementation details. In this chapter, we’ll look at the easier options.

3.1 Changing stylesheet parameters

The DocBook xslTNG Stylesheets define a lot of parameters. They are all described in Reference I, Parameter reference. If the change you want to make has already been parameterized, you may be able to achieve your goal simply by setting a parameter at runtime.

For example, if you want to change the formatting of dates and times in date elements, you can simply change the date and time formatting parameters. Similarly, if you want to change the numeration style of ordered lists, you can simply change the ordered list item numeration parameter.

These changes can be accomplished by simply passing the new values to the processor, on the command line or in a configuration file, for example. You do not have to write any XSLT to make these changes.

Parameter values apply to the entire document processed by the stylesheets. In some cases, you may wish to change the presentation of just one or small number of elements. This can often be accomplished with a db processing instruction in the source document itself. These customizations can also be accomplished without writing any XSLT.

If you want to make a change that isn’t supported by a parameter, or an ad hoc exception that doesn’t have a supporting processing instruction, you will have to write a customization layer. (You are invited to submit an issue with your use case if you think it would be of general interest.)

You may also find it convenient to write a customization layer if you want to change several parameters and you find it inconvenient to pass them all to the processor on every invocation.

3.2 Creating a customization layer

A customization layer is simply an XSLT stylesheet that you write which extends the DocBook stylesheets. The simplest* customization layer is:

1<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:db="http://docbook.org/ns/docbook"
5    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.w3.org/1999/xhtml"
    exclude-result-prefixes="db xs"
    version="3.0">
 
10<!-- This href has to point to your local copy
     of the stylesheets. -->
<xsl:import href="docbook/xslt/docbook.xsl"/>
 
</xsl:stylesheet>

This customization doesn’t do anything. But you can, for example, redefine parameters if you wish:

1<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:db="http://docbook.org/ns/docbook"
5    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.w3.org/1999/xhtml"
    exclude-result-prefixes="db xs"
    version="3.0">
 
10<xsl:import href="docbook/xslt/docbook.xsl"/>
 
<xsl:param name="orderedlist-item-numeration"
           select="'1'"/>
 
15<xsl:param name="date-dateTime-format"
           select="'[D01] [MNn,*-3] [Y0001]
                   at [H01]:[m01]'"/>
 
</xsl:stylesheet>

This will have the effect of running the DocBook stylesheets with those two parameters set as specified.

If you want to change the HTML output for an element, you can write a template for that element in your customization layer. Consider this DocBook document:

1<?xml version="1.0" encoding="utf-8"?>
<article xmlns="http://docbook.org/ns/docbook"
         version="5.1">
<info>
5<title>Sample Document</title>
<date>2020-07-05</date>
</info>
 
<para>This is a sample <productname>DocBook</productname>
10document.</para>
 
</article>

Suppose that you decided you wanted to have the productname element link automatically to the vendor webpage.

☝︎
Important

The DocBook xslTNG Stylesheets process all DocBook elements in the m:docbook mode. This is different from previous XSLT stylesheets for DocBook which simply used the default mode.

You must either specify a default mode in your customization layer or remember to specify the mode on match templates and template applications. If you forget the mode, you’ll get unexpected results!

One way to do that would be to redefine the template that processes the productname element:

1<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:db="http://docbook.org/ns/docbook"
5    xmlns:m="http://docbook.org/ns/docbook/modes"  
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.w3.org/1999/xhtml"
    exclude-result-prefixes="db m xs"  
    version="3.0">
10 
<xsl:import href="docbook/xslt/docbook.xsl"/>
 
<xsl:param name="orderedlist-item-numeration"
           select="'1'"/>
15 
<xsl:param name="date-dateTime-format"
           select="'[D01] [MNn,*-3] [Y0001]
                   at [H01]:[m01]'"/>
 
20<xsl:template match="db:productname"
              mode="m:docbook">  
  <xsl:variable name="name"
                select="normalize-space(.)"/>

25  <xsl:variable name="url" as="xs:string?">
    <xsl:choose>
      <xsl:when test="$name='DocBook'">
        <xsl:sequence select="'https://docbook.org/'"/>
      </xsl:when>
30      <xsl:when test="$name='DocBook xslTNG Stylesheets'">
        <xsl:sequence select="'https://xsltng.docbook.org/'"/>
      </xsl:when>
      <xsl:when test="$name='Wikipedia'">
        <xsl:sequence select="'https://wikipedia.org/'"/>
35      </xsl:when>
      <xsl:otherwise>
        <!-- Unrecognized -->
      </xsl:otherwise>
    </xsl:choose>
40  </xsl:variable>
                  
  <xsl:choose>
    <xsl:when test="empty($url)">
      <xsl:next-match/>  
45    </xsl:when>
    <xsl:otherwise>
      <a href="{$url}" title="Home page">
        <xsl:next-match/>  
      </a>
50    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
 
</xsl:stylesheet>

All of the DocBook elements are processed in the “m:docbook” mode.

Remember to exclude all the namespaces you declare so that they don’t wind up scattered about in your HTML.

I repeat, all of the DocBook elements are processed in the “m:docbook” mode. I expect failure to declare this mode is going to be a common error.

Yes, this whole listing is rather cramped. I’m trying to make it all narrow enough to fit in the display without making horizontal scrolling necessary.

Calling xsl:next-match invokes the underlying processing. The effect of this template is to wrap an HTML “a” around the default processing for productname.

It’s worth pointing out that if the tag has an xlink:href attribute, that will generate an HTML a as well. A more robust stylesheet would check for that, but I’m trying to keep the example simple.