At some point in your customization efforts you may find that none of the above methods will achieve the result you want. The most powerful customization method is to replace specific XSL templates in the DocBook collection with your own customized templates. The general technique is:
Find the DocBook XSL template that handles the text you want to change.
Copy that template to your customization layer.
Modify the copy to do what you want. Your version will override the behavior of the standard template because yours has a higher import precedence.
This method is very powerful, but it is not easy. It requires extensive knowledge of XSLT programming, and familiarity with the internals of the DocBook XSL stylesheet collection. This customization method is possible because the DocBook stylesheets are written in a highly modular fashion.
Here is a simple example of a template replacement. The default formatting for the
command element is boldface. Perhaps you prefer your commands to appear in a monospaced font. In the collection of files for the DocBook XSL distribution, you will find
html/inline.xsl that contains this
<xsl:template match="command"> <xsl:call-template name="inline.boldseq"/> </xsl:template>
Also in that file you will notice a template named
inline.monoseq that does what you want. So you can add the following template to your customization layer to change how
command is formatted:
<xsl:template match="command"> <xsl:call-template name="inline.monoseq"/> </xsl:template>
You can see a longer example of rewriting a template in the section “Customizing TOC presentation”.
Most DocBook templates perform a very specific and limited function. The trick is to find the template that is handling the behavior you want to change. Typically many templates are called during the processing of a given element. Depending on what you are trying to change, you may have to trace through several templates to find the one you need to replace.
There are two basic kinds of XSLT template:
Templates that have a
match attribute, which are called during
xsl:apply-templates when the processor encounters an element satisfying the match pattern.
Templates that have a
name attribute and are called by name like a subroutine using
If you are trying to change how a particular element is handled, you can usually start by scanning for
match attributes that include the name of your element. Sometimes there will be more than one template whose
match attribute could apply. Then the processor generally selects the one with the best match, that is, the most specific match. For example, a match pattern of
chapter/para is more specific than
para. The more specific the match, the higher the priority in selecting that template.
Once you have found the starting point, you can trace through the template body to see what other templates it uses. Named templates are explicitly called by name using
xsl:call-template. Those templates are easy to find because there is only one for each name.
If a template uses
xsl:apply-templates, then you need to consider several factors that affect which template might be applied:
xsl:apply-templates includes a
select attribute, then those elements matched by the select expression are going to be processed. So you need to find templates with
match attributes that apply to those elements.
xsl:apply-templates does not include a
select attribute, then the children of the current element will be processed. So you need to look for templates with
match attributes that apply to the children.
xsl:apply-templates includes a
mode attribute, then you can narrow your search to those matching templates that have the same mode value.
You may need to look in several directories to find the right template. Most of the templates for HTML processing are in the
html subdirectory of the stylesheet distribution, and most of the templates for generating FO output are in the
fo subdirectory. But they share templates in the
lib directories, so you may need to look there as well. Here is a handy Linux command for searching three directories at once, showing how to find all references to
find html lib common -name '*.xsl' | xargs grep 'href.target'
This command is run in the directory above
html. It uses find to search the
common directories for files named
*.xsl. It uses the xargs command to feed that list to the grep command that scans each file for the given regular expression. If you are a Windows user, this command is available if you install Cygwin.
Hopefully at some point you will find the specific template that does the processing you want to change. That's the template you want to duplicate and modify in your customization layer.
When you add overriding templates to your customization layer, you have to pay attention to XSLT import precedence. This says that the importing stylesheet's templates take precedence over the imported stylesheet's templates. In general, that is what you want, since that is how you override the behavior of the stock template.
But what isn't obvious is that import precedence is stronger than priority selection. Within a stylesheet, a match pattern that is more specific has a higher priority than a less specific pattern. So a template with
match="formalpara/para" has a higher priority than a template with
match="para". That's how you get templates to apply in certain contexts but not others. But import precedence can override this priority selection.
A detailed example will make this easier to understand. In the DocBook stylesheet file
html/block.xsl, there is a
<xsl:template match="para"> template for general
para elements that outputs HTML
<p></p> tags around its content. There is another
<xsl:template match="formalpara/para"> template for a
para within a
formalpara element. It does not output
<p></p> tags, because the wrapper element's template
match="formalpara" does that, so that the title and the para are in one set of
<p></p> tags. The more specific template has a higher priority in the DocBook stylesheet.
Now copy the
<xsl:template match="para"> template to your customization layer. Now your
formalpara elements will start generating invalid HTML, because there will be nested
<p></p> tags, which is not permitted in HTML. The reason you get this error is because your
match="para" template now has higher import precedence than the
match="formalpara/para" template in
block.xsl, even though your template is less specific. The import precedence is stronger than the match priority.
The solution is to provide another template in your customization layer:
<xsl:template match="formalpara/para"> <xsl:apply-imports/> </xsl:template>
Now this template has equal import precedence to your
match="para" template, because they are both in the importing stylesheet. It also has a higher priority since it is more specific. So it will be used for any
para elements inside
formalpara. Its effect is to just apply the original such template in
block.xsl, which avoids the nested
<xsl:template name="href.target"> <xsl:param name="context" select="."/> <xsl:param name="object" select="."/> ...
Such a template may be called with one or more of the parameters set. For example:
<xsl:call-template name="href.target"> <xsl:with-param name="context" select="
some-context"/> <xsl:with-param name="object" select="
some-object"/> ... </xsl:call-template>
You want your new template to fit in as a direct replacement for the original, so it should handle the same parameters as the original. Since it is not required that all parameters be passed when a template is called, it should also handle missing parameter values. This requires you to understand when parameters are passed, what might be passed as a parameter value, and how it is expected to be handled. So if you are modifying a named template, check all the templates that call the template you are modifying to see what they do with the parameters.
You may extend a modified template by passing it new parameters. Be sure to declare your new parameters with a default value at the top of your new template. Of course, you'll also have to replace one or more of the calling templates so they can pass the parameter to your new template. You don't have to replace all of the calling templates, since parameters are optional. But you do need to make sure your default value works in case they don't pass a value.
|DocBook XSL: The Complete Guide - 3rd Edition||PDF version available|
Copyright © 2002-2005 Sagehill Enterprises