Sponsoring The Perl Toolchain Summit 2025: Help make this important event another success Learn more

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Customizing DocBook XSL stylesheets</title><link rel="stylesheet" href="reference.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.37"><link rel="home" href="index.html" title="DocBook XSL Stylesheet Documentation"><link rel="up" href="publishing.html" title="Chapter 1. DocBook XSL"><link rel="previous" href="ch01s03.html" title="XSL processing model"><link rel="next" href="extensions.html" title="Chapter 2. Saxon Extensions"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Customizing DocBook XSL stylesheets</th></tr><tr><td width="20%" align="left"><a href="ch01s03.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter 1. DocBook XSL</th><td width="20%" align="right">&nbsp;<a href="extensions.html">Next</a></td></tr></table><hr></div><p>The DocBook XSL stylesheets are written in a modular
fashion. Each of the HTML and FO stylesheets starts with a
driver file that assembles a collection of component files
into a complete stylesheet. This modular design puts similar things together into smaller files that are easier to write and maintain than one big stylesheet. The modular stylesheet files
are distributed among four directories:</p><div class="variablelist"><dl><dt><a name="c44b1b3b7b3b1"></a><span class="term">common/</span></dt><dd><p><a name="c44b1b3b7b3b1b2"></a>contains code common to both stylesheets, including localization data
</p></dd><dt><a name="c44b1b3b7b3b2"></a><span class="term">fo/</span></dt><dd><p><a name="c44b1b3b7b3b2b2"></a>a stylesheet that produces XSL FO result trees
</p></dd><dt><a name="c44b1b3b7b3b3"></a><span class="term">html/</span></dt><dd><p><a name="c44b1b3b7b3b3b2"></a>a stylesheet that produces HTML/XHTML result trees
</p></dd><dt><a name="c44b1b3b7b3b4"></a><span class="term">lib/</span></dt><dd><p><a name="c44b1b3b7b3b4b2"></a>contains schema-independent functions
</p></dd></dl></div><p>The driver files for each of HTML and FO stylesheets
are <tt>html/docbook.xsl</tt> and <tt>fo/docbook.xsl</tt>,
respectively. A driver file consists mostly of a bunch
of <tt>&lt;xsl:include&gt;</tt> instructions to
pull in the component templates, and then defines some
top-level templates. For example:</p><pre class="programlisting">&lt;xsl:include href="../VERSION"/&gt;
&lt;xsl:include href="../lib/lib.xsl"/&gt;
&lt;xsl:include href="../common/l10n.xsl"/&gt;
&lt;xsl:include href="../common/common.xsl"/&gt;
&lt;xsl:include href="autotoc.xsl"/&gt;
&lt;xsl:include href="lists.xsl"/&gt;
&lt;xsl:include href="callout.xsl"/&gt;
...
&lt;xsl:include href="param.xsl"/&gt;
&lt;xsl:include href="pi.xsl"/&gt;
</pre><p>The first four modules are shared with the FO
stylesheet and are referenced using relative pathnames to
the common directories. Then the long list of component
stylesheets starts. Pathnames in include statements are
always taken to be relative to the including file. Each
included file must be a valid XSL stylesheet, which means
its root element must
be <tt>&lt;xsl:stylesheet&gt;</tt>.</p><div class="sect2"><a name="c44b1b3b7b7"></a><div class="titlepage"><div><h3 class="title"><a name="c44b1b3b7b7"></a>Stylesheet inclusion vs. importing</h3></div></div><p>XSL actually provides two inclusion
mechanisms: <tt>&lt;xsl:include&gt;</tt> and <tt>&lt;xsl:import&gt;</tt>.
Of the two, <tt>&lt;xsl:include&gt;</tt> is
the simpler. It treats the included content as if it were
actually typed into the file at that point, and doesn't
give it any more or less precedence relative to the
surrounding text. It is best used when assembling
dissimilar templates that don't overlap what they match.
The DocBook driver files use this instruction to assemble a
set of modules into a stylesheet.</p><p>In contrast, <tt>&lt;xsl:import&gt;</tt> lets
you manage the precedence of templates and variables. It is
the preferred mode of customizing another stylesheet because
it lets you override definitions in the distributed
stylesheet with your own, without altering the distribution
files at all. You simply import the whole stylesheet and
add whatever changes you want.</p><p>The precedence rules for import are detailed and
rigorously defined in the XSL standard. The basic rule is
that any templates and variables in the importing
stylesheet have precedence over equivalent templates and
variables in the imported stylesheet. Think of the imported stylesheet elements as a fallback collection, to be used only if a match is not found in the current stylesheet. You can customize the templates you want to change in your stylesheet file, and let the imported stylesheet handle the rest.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title"><a name="c44b1b3b7b7b5"></a>Note</h3><p>Customizing a DocBook XSL stylesheet is the opposite
of customizing a DocBook DTD. When you customize a DocBook
DTD, the rules of XML and SGML dictate that
the <i>first</i> of any duplicate declarations
wins. Any subsequent declarations of the same element or
entity are ignored. The architecture of the DTD provides
slots for inserting your own custom declarations early
enough in the DTD for them to override the standard
declarations. In contrast, customizing an XSL stylesheet is
simpler because your definitions have precedence over imported ones.</p></div><p>You can carry modularization to deeper levels because
module files can also include or import other modules.
You'll need to be careful to maintain the precedence that
you want as the modules get rolled up into a complete
stylesheet. </p></div><div class="sect2"><a name="c44b1b3b7b8"></a><div class="titlepage"><div><h3 class="title"><a name="c44b1b3b7b8"></a>Customizing
with <tt>&lt;xsl:import&gt;</tt></h3></div></div><p>There is currently one example of customizing
with <tt>&lt;xsl:import&gt;</tt> in the HTML
version of the DocBook stylesheets.
The <tt>xtchunk.xsl</tt> stylesheet modifies the
HTML processing to output many smaller HTML files rather
than a single large file per input document. It uses XSL
extensions defined only in the XSL
processor <b>XT</b>. In the driver
file <tt>xtchunk.xsl</tt>, the first instruction
is <tt>&lt;xsl:import
href="docbook.xsl"/&gt;</tt>. That instruction imports
the original driver file, which in turn uses
many <tt>&lt;xsl:include&gt;</tt> instructions to
include all the modules. That single import instruction
gives the new stylesheet the complete set of DocBook
templates to start with.</p><p>After the
import, <tt>xtchunk.xsl</tt> redefines some of
the templates and adds some new ones. Here is one example
of a redefined template:</p><pre class="programlisting">Original template in autotoc.xsl
&lt;xsl:template name="href.target"&gt;
&lt;xsl:param name="object" select="."/&gt;
&lt;xsl:text&gt;#&lt;/xsl:text&gt;
&lt;xsl:call-template name="object.id"&gt;
&lt;xsl:with-param name="object" select="$object"/&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:template&gt;
New template in xtchunk.xsl
&lt;xsl:template name="href.target"&gt;
&lt;xsl:param name="object" select="."/&gt;
&lt;xsl:variable name="ischunk"&gt;
&lt;xsl:call-template name="chunk"&gt;
&lt;xsl:with-param name="node" select="$object"/&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:variable&gt;
&lt;xsl:apply-templates mode="chunk-filename" select="$object"/&gt;
&lt;xsl:if test="$ischunk='0'"&gt;
&lt;xsl:text&gt;#&lt;/xsl:text&gt;
&lt;xsl:call-template name="object.id"&gt;
&lt;xsl:with-param name="object" select="$object"/&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:if&gt;
&lt;/xsl:template&gt;
</pre><p>The new template handles the more complex processing
of HREFs when the output is split into many HTML files.
Where the old template could simply
output <tt>#<i><tt>object.id</tt></i></tt>,
the new one outputs <tt><i><tt>filename</tt></i>#<i><tt>object.id</tt></i></tt>.</p></div><div class="sect2"><a name="c44b1b3b7b9"></a><div class="titlepage"><div><h3 class="title"><a name="c44b1b3b7b9"></a>Setting stylesheet variables</h3></div></div><p>You may not have to define any new templates,
however. The DocBook stylesheets are parameterized using
XSL variables rather than hard-coded values for many of the
formatting features. Since
the <tt>&lt;xsl:import&gt;</tt> mechanism also
lets you redefine global variables, this gives you an easy
way to customize many features of the DocBook
stylesheets. Over time, more features will be parameterized to permit customization. If you find hardcoded values in the stylesheets that would be useful to customize, please let the maintainer know.</p><p>Near the end of the list of includes in the main
DocBook driver file is the
instruction <tt>&lt;xsl:include
href="param.xsl"/&gt;</tt>.
The <tt>param.xsl</tt> file is the most
important module for customizing a DocBook XSL stylesheet.
This module contains no templates, only definitions of
stylesheet variables. Since these variables are defined
outside of any template, they are global variables and
apply to the entire stylesheet. By redefining these
variables in an importing stylesheet, you can change the
behavior of the stylesheet.</p><p>To create a customized DocBook stylesheet, you simply
create a new stylesheet file such
as <tt>mystyle.xsl</tt> that imports the standard
stylesheet and adds your own new variable definitions. Here
is an example of a complete custom stylesheet that changes
the depth of sections listed in the table of contents from
two to three:</p><pre class="programlisting">&lt;?xml version='1.0'?&gt;
&lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'
exclude-result-prefixes="#default"&gt;
&lt;xsl:import href="docbook.xsl"/&gt;
&lt;xsl:variable name="toc.section.depth"&gt;3&lt;/xsl:variable&gt;
&lt;!-- Add other variable definitions here --&gt;
&lt;/xsl:stylesheet&gt;
</pre><p>Following the opening stylesheet element are the
import instruction and one variable definition. The
variable <tt>toc.section.depth</tt> was defined
in <tt>param.xsl</tt> with value "2", and here
it is defined as "3". Since the importing stylesheet takes
precedence, this new value is used. Thus documents
processed with <tt>mystyle.xsl</tt> instead
of <tt>docbook.xsl</tt> will have three levels
of sections in the tables of contents, and all other
processing will be the same.</p><p>Use the list of variables
in <tt>param.xsl</tt> as your guide for creating
a custom stylesheet. If the changes you want are controlled
by a variable there, then customizing is easy. </p></div><div class="sect2"><a name="c44b1b3b7c10"></a><div class="titlepage"><div><h3 class="title"><a name="c44b1b3b7c10"></a>Writing your own templates</h3></div></div><p>If the changes you want are more extensive than what
is supported by variables, you can write new templates. You
can put your new templates directly in your importing
stylesheet, or you can modularize your importing stylesheet
as well. You can write your own stylesheet module
containing a collection of templates for processing lists,
for example, and put them in a file
named <tt>mylists.xsl</tt>. Then your importing
stylesheet can pull in your list templates with
a <tt>&lt;xsl:include
href="mylists.xsl"/&gt;</tt> instruction. Since your
included template definitions appear after the main import
instruction, your templates will take precedence.</p><p>You'll need to make sure your new templates are
compatible with the remaining modules, which means:</p><div class="itemizedlist"><ul><li><p><a name="c44b1b3b7c10b4b1"></a>Any named templates should use the same name so
calling templates in other modules can find them.</p></li><li><p><a name="c44b1b3b7c10b4b2"></a>Your template set should process the same elements
matched by templates in the original module, to ensure
complete coverage.</p></li><li><p><a name="c44b1b3b7c10b4b3"></a>Include the same set
of <tt>&lt;xsl:param&gt;</tt> elements in each
template to interface properly with any calling templates,
although you can set different values for your
parameters.</p></li><li><p><a name="c44b1b3b7c10b4b4"></a>Any templates that are used like subroutines to
return a value should return the same data type.</p></li></ul></div></div><div class="sect2"><a name="c44b1b3b7c11"></a><div class="titlepage"><div><h3 class="title"><a name="c44b1b3b7c11"></a>Writing your own driver</h3></div></div><p>Another approach to customizing the stylesheets is to
write your own driver file. Instead of
using <tt>&lt;xsl:import
href="docbook.xsl"/&gt;</tt>, you copy that file to a
new name and rewrite any of
the <tt>&lt;xsl:include/&gt;</tt> instructions to
assemble a custom collection of stylesheet modules. One
reason to do this is to speed up processing by reducing the
size of the stylesheet. If you are using a customized
DocBook DTD that omits many elements you never use, you
might be able to omit those modules of the
stylesheet.</p></div><div class="sect2"><a name="c44b1b3b7c12"></a><div class="titlepage"><div><h3 class="title"><a name="c44b1b3b7c12"></a>Localization</h3></div></div><p>The DocBook stylesheets include features for
localizing generated text, that is, printing any generated
text in a language other than the default English. In
general, the stylesheets will switch to the language
identified by a <tt>lang</tt> attribute when
processing elements in your documents. If your documents
use the <tt>lang</tt> attribute, then you don't
need to customize the stylesheets at all for
localization.</p><p>As far as the stylesheets go,
a <tt>lang</tt> attribute is inherited by the
descendents of a document element. The stylesheet searches
for a <tt>lang</tt> attribute using this XPath
expression:</p><pre class="programlisting">&lt;xsl:variable name="lang-attr"
select="($target/ancestor-or-self::*/@lang
|$target/ancestor-or-self::*/@xml:lang)[last()]"/&gt;</pre><p>This locates the attribute on the current element or
its most recent ancestor. Thus
a <tt>lang</tt> attribute is in effect for an
element and all of its descendents, unless it is reset in
one of those descendents. If you define it in only your
document root element, then it applies to the whole
document:</p><pre class="programlisting">&lt;?xml version="1.0"?&gt;
&lt;!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.0//EN" "docbook.dtd"&gt;
&lt;book lang="fr"&gt;
...
&lt;/book&gt;</pre><p>When text is being generated, the stylesheet checks
the most recent <tt>lang</tt> attribute and looks
up the generated text strings for that language in a
localization XML file. These are located in
the <tt>common</tt> directory of the
stylesheets, one file per language. Here is the top of the
file <tt>fr.xml</tt>:</p><pre class="programlisting">&lt;localization language="fr"&gt;
&lt;gentext key="abstract" text="R&amp;#x00E9;sum&amp;#x00E9;"/&gt;
&lt;gentext key="answer" text="R:"/&gt;
&lt;gentext key="appendix" text="Annexe"/&gt;
&lt;gentext key="article" text="Article"/&gt;
&lt;gentext key="bibliography" text="Bibliographie"/&gt;
...
</pre><p>The stylesheet templates use the gentext key names,
and then the stylesheet looks up the associated text value
when the document is processed with that lang setting. The
file <tt>l10n.xml</tt> (note
the <tt>.xml</tt> suffix) lists the filenames of
all the supported languages.</p><p>You can also create a custom stylesheet that sets the
language. That might be useful if your documents don't make
appropriate use of the <tt>lang</tt> attribute.
The module <tt>l10n.xsl</tt> defines two global
variables that can be overridden with an importing
stylesheet as described above. Here are their default
definitions:</p><pre class="programlisting">&lt;xsl:variable name="l10n.gentext.language"&gt;&lt;/xsl:variable&gt;
&lt;xsl:variable name="l10n.gentext.default.language"&gt;en&lt;/xsl:variable&gt;
</pre><p>The first one sets the language for all elements,
regardless of an element's <tt>lang</tt> attribute
value. The second just sets a default language for any
elements that haven't got a <tt>lang</tt> setting
of their own (or their ancestors).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a href="ch01s03.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a href="index.html">Home</a></td><td width="40%" align="right">&nbsp;<a href="extensions.html">Next</a></td></tr><tr><td width="40%" align="left">XSL processing model&nbsp;</td><td width="20%" align="center"><a href="publishing.html">Up</a></td><td width="40%" align="right">&nbsp;Chapter 2. Saxon Extensions</td></tr></table></div></body></html>