The DoCookBook

Recipies for DocBook Developers

Thomas Schraitle

Published: 06 May 2012, 18:10 +02:00

Draft (Version 0.5)

Draft Ahead!

This book is a draft and still work in progress. You will find funny typos, embarrassing English grammar mistakes from a German native speaker, annoying inconsistencies, missing topics, and plain errors. Nevertheless, I hope the topics are useful and should give you an idea.

Visit this site from time to time and see how the book grows and how more and more of these annoyances will vanish. To accelerate this process, send me praise, critisism, patches, donations, or even write a topic. Read Section 1.6, “Contribute to the Book” to find more how to support this project.

Revision History
0.5 22 Apr 2012 Thomas Schraitletoms
 

Fifth public release, see https://sf.net/mailarchive/message.php?msg_id=29164534

0.4 29 Jan 2012 Thomas Schraitletoms
 

Fourth public release, see https://sf.net/mailarchive/message.php?msg_id=28755847

0.3 28 Dec 2011 Thomas Schraitletoms
 

Third public release, see http://sf.net/mailarchive/message.php?msg_id=28599375

0.2 23 Dec 2011 Thomas Schraitletoms
 

Second public release, see http://sf.net/mailarchive/message.php?msg_id=28585391

0.1 07 Dec 2011 Thomas Schraitletoms
 

First public revision announced


Table of Contents

List of Tables

List of Examples

Welcome!

Mission

The DoCookBook Project aims to create an open source book about DocBook and the DocBook XSL stylesheets written in a cookbook and released under Creative Commons license.

According to its homepage, “DocBook is a schema (available in several languages including RELAX NG, SGML and XML DTDs, and W3C XML Schema) maintained by the DocBook Technical Committee of OASIS. It is particularly well suited to books and papers about computer hardware and software (though it is by no means limited to these applications).

Although there are helpful and valuable documentation―be it as a printed book[1] or online[2]―I always felt there is a gap. This gap could be bridged with a guide that only concentrates on problems and their solution in a concise manner explained by step-by-step procedures. Until now nobody wrote a book that combines possible problems, pitfalls, “how to do this”, and the benefits in a cookbook style. My book is intented to be such a book. However, it does not seek to replace any other information, be it printed or online. It aims for enhancing the world of DocBook with a different view.

The topics in this book are mostly based on my own experiences with DocBook and the DocBook XSL stylesheets. However, it also includes questions and answers from other sources: from the DocBook mailinglists, other sites that inspired me, or questions from collegues. It is the nature of such topics that there might be some overlap with other sources. When other authors inspired me, I have included their names. If you think your name is missing, please let me know.

As I have learned (and still do) a lot from the masters of DocBook, it is time to give something back. What you are reading is the first draft of the fruits of these efforts. Currently, this book is available under a Creative Commons license (see License if you want to know more). I hope you enjoy reading this book as much as I enjoy writing it.

This book covers topics which range from very easy to pretty demanding. The more challenging a problems is the more you need experience from different domains (CSS, FO, XSLT, etc.) As such, this book does not and cannot attempt to teach you DocBook or any such related technology (with the exception of Chapter 1, Knowing DocBook’s Structure). If you want to learn DocBook or need some help with XML or XSLT, search elsewhere. There are plenty of information available either online or printed.

This book is aimed at DocBook users who write and seek answers for their customization problems. However, with some try-and-error, it can also be useful for ordinary writers who want to try something out. For readers who want further information, links are included in the See Also section at the end of each topic.

Although a lot of these topics can be used for both versions with minimal changes, this book focuses on DocBook 5. Why? There are several reasons:

  • DocBook 4 is in maintenance mode and DocBook 5 is the future.

  • I wanted to show exhaustive examples for DocBook 5. With this book, I hope, users can learn how to adopt and use it.

  • It is easy to transform DocBook 4 into version 5 as shown in Section 3.3, “Converting DocBook from Version 4 to Version 5”.

  • It simplifies writing a lot if you can concentrate on only one version and not on two. It is also easier to read for you.

The differences are documented in the DocBook5: The Definitive Guide book, section What’s New in DocBook V5.0?.

Apart from the DocBook examples, the transformation examples are currently based on the DocBook XSL 1.0 stylesheets. They are stable, well-documented and can be used with any XSLT 1.0 processor.

On the other side, there is always the tension between implementing new concepts and retaining backward compatibility. For this reason, the XSLT 1.0 stylesheets are rewritten for XSLT 2.0. This task is not finished yet. As soon as they are production-stable, they will be covered in this book too.

By no means is this book complete. As this book is based on technologies like CSS, XML, (X)HTML, and XSLT, it is always a good idea to seek other information. I highly recommend to read the books by Norman Walsh and Bob Stayton as mentioned before.

The following typographical conventions are used in this book:

  • Italic is used for definition of new terms or emphasised text.

  • Monospace text is used for code listings, XML structures, URLs, filenames, namespaces, or links.

  • Monospace bold text for commands or emphasised text in listings.

  • Monospace italic text is used for placeholders in listings.

The project is hosted on SourceForge under the name DocCookBook. Feel free to send me praise, constructive criticism, suggestions, ideas, improvements, or anything else.

The source code of this book is published and maintained as a Mercurial repository. Feel free to clone it, make improvements and mail me your changes to .

Getting a copy takes just a few seconds. If you have Mercurial already installed on your system, run the following command:

hg clone https://hg.code.sf.net/p/doccookbook/code doccookbook

Mercurial is a free, distributed version control system and available for Mac, Linux, and Windows. Download it from http://mercurial.selenic.com.

If you do not want to change the source code, but want to contribute, open a ticket. Describe your bugs, grammar errors, typos, or other inconveniences you have found and add them to the list at http://sf.net/p/doccookbook/tickets/.

If you are reading this text online, you may have noticed that this project uses Piwik. According to its home page, Piwik is a “real time web analytics software program”. The results from Piwik give me detailed reports about my Web site visitors: where do they come from, which browser and operating system they use and so on.

Why Piwik? First it is open source, but that is not the main reason. The main reason why I use Piwik is it collects data anonymously to create statistical studies. With these results I can not only improve the HTML page but make the whole project better.

For example, if my visitors browsing the Web through Firefox, Opera, and Chromium instead of Internet Explorer, I can focus more on the first three browsers. Focusing on one area gives me more time to write cool new topics. Or improve existing text. Or draw nice graphics. Furthermore with the collected data I can see which topics are the most popular and which needs additional devotion. I hope you get the idea.

Just to make it clear: The collected data is completely anonymous and only used to improve this project. It will never be sold nor will it be used to spam you.

The book is currently released under a Creative Commons CC BY-NC-SA 3.0 DE license (see original German text in Appendix A or the English translation in Appendix B). After this book is finished, the license will be changed to CC BY-SA 3.0 DE.

Such a large project is usually not a one man show. Many people contributed to this book:

  • Antje Faber for proofreading some of my texts and the original idea.

  • Stefan Hinz for providing me with valuable feedback and improvements.

  • Lars Vogel for his suggestions and improvements.

  • Norman Walsh for DocBook, the DocBook stylesheets, and all the nice tools that makes live with DocBook so much easier.

  • Matthias Weckbecker for helping me with some wording and ideas.


[1]Like the reference DocBook 5: The Definitive Guide from Norman Walsh or Bob Stayton's DocBook XSL

[2]Dave Pawson maintains a DocBook FAQ and the previous mentioned books can be found online too.

Chapter 1. Knowing DocBook’s Structure

DocBook has a wide variety of elements covering different semantics: from structural elements like book, chapter, appendix, to block elements like orderedlist, table, figure, to inline elements like filename, quote, or link. All of these elements are well covered in The Definitive Guide. This chapter shows more the unknown parts and how to avoid pitfalls and improve consistency throughout your documentation.

TBD
To successfully use DocBook you basically need to know how to transform your ideas into (DocBook's) structure. Usually, the DocBook elements are mostly self-explanatory: if you want to write a book, use book, for a chapter use chapter and so on. All you need is covered in the Definitive Guide with examples and the reference of all elements.

However, a reference usually do not cover the finer details, what is the recommended practise, or recommendations.

Difficulty: ★☆☆ (easy)
Keywords: XInclude, module, assemblies, XPointer

Problem

You need a method to split your document into several “modules” and put it together afterwards.

Solution

Use XInclude. It is a W3C specification and defines the elements xi:include and xi:fallback. They are not DocBook elements (as they are definied by the W3C and not OASIS), however they have been integrated in version 5.x[3]. Note, XIncludes work in DocBook regardless which version (4.x or 5.x) you use.

If you want to use XIncludes, you need these things:

  • A XML parser who supports XIncludes.

  • The element xi:include. In general, it can be placed almost everywhere. It is a “pointer” to the file which is going to be included.

  • The attribute href inside the xi:include element. It is an URI which refers to your included file.

  • The file which is referenced by the href attribute. The content of the file will replace the xi:include element.

The following example shows a book which points to a substructure assuming chapters:

Example 1.1. A Book with XIncluded Chapters
  1 <book version="5.0"
  2   xmlns="http://docbook.org/ns/docbook"
      xmlns:xi="http://www.w3.org/2001/XInclude">
  4   <title>...</title>
      <xi:include href="intro.xml"/>
  6   <xi:include href="conceptual-overview.xml"/>
    </book>

The above book contains an introduction (file intro.xml) and a conceptual overview (file conceptual-overview.xml). Both are referenced by the XInclude´s href attribute.

Before you transform your document, you need to resolve your XIncludes, either by your XML parser or “manually” by a XSLT transformation. The following procedure shows a typical workflow:

Typical Workflow with XIncludes
  1. Write your document structure, usually it will be a book or an article. Do not forget to include the XInclude namespace http://www.w3.org/2001/XInclude into the root element. It is common to use the prefix xi.

  2. Add xi:include elements for those elements you want to maintain in a separate file. Typically, this can be an appendix, chapter, preface, glossary, or any other top level elements.

  3. Resolve your XIncludes. Use a XML parser who supports XIncludes, for example, xmllint from the libxml2 library. This XML parser brings the --xinclude option to resolve all your XInclude elements in one step:

    xmllint --xinclude --output big.xml book.xml

    The above command resolves all XIncludes and saves the result in the file big.xml. Note, this does not perform any validation! It just replaces xi:include with the content of the referenced file. After the XInclude elements are resolved, the file looks now like this:

      1 <book version="5.0"
      2   xmlns="http://docbook.org/ns/docbook"
          xmlns:xi="http://www.w3.org/2001/XInclude">
      4   <title>...</title>
          <chapter>
      6     <title>Introduction</title>
            <para>...</para>
      8   </chapter>
          <chapter>
     10    <title>Conceptual Overview</title>
           <para>...</para>
     12   </chapter>
        </book>
  4. Validate the result (in our example, it is big.xml) with your DocBook schema.

  5. Transform the result file with your stylesheets into your output format.

Discussion

The previous procedure showed a book with xincluded chapters. It is possible to even go deeper and include also section into a chapter. Actually, there is no limit. You should only be aware that you do not create circular references (file A includes file B and B includes A).

As XIncludes are very common nowadays, resolving xi:include and transforming into the output format can be done in one step. This is the case for xsltproc from the libxslt library. Use the --xinclude option as shown:

xsltproc --xinclude STYLESHEET XMLFILE

If you prefer Saxon, version 9 contains the -xi option to resolve XIncludes:

saxon9 -xi -xsl:STYLESHEET -s:XMLFILE

The last section showed a general method to work with XIncludes. In most cases this is enough. However, XIncludes offers more benefits which are discovered in the following subsections.

Fallbacks

If the referenced file in the xi:include element is not available, the XInclude step will fail. How can you avoid that? The XInclude specification defines also the xi:fallback element. This element can be used to add code when a referenced resource could not be retrieved:

Example 1.2. Fallback Possibility with xi:fallback
  1 <xi:include href="revhistory.xml">
  2   <xi:fallback>
        <para>The revision history could not be retrieved.</para>
  4   </xi:fallback>
    </xi:include>

The previous code does the following: When the xi:include element is being processed, the XML parser tries to include the file revhistory.xml. If the file can not be retrieved, the XML parser will consider the xi:fallback element and include the contents. In the above case it includes a para element showing the failed attempt.

This method is useful when you want to process files which cannot be expected to always be there. For example, the previous revision history needs to be generated first. However, it is not always sure that the revision history can be generated from an possible offline version control system.

Including Text

The previous examples dealt with included resources in XML only. If you need to include text, this can also be done with XInclude.

Most common usecase is including source code which is maintained separately. The following example points to a C source code which needs to be included as text:

Example 1.3. Included Text in a Programlisting
  1 <programlisting language="c"><xi:include
  2    parse="text"
       href="parser.c"/></programlisting>

The important line is parse="text". This advises the XInclude processor to handle the referenced file just as text and not as XML. The default value for parse is xml.

It is recommended to remove any whitespaces inside programlisting as shown above to avoid spurious indendation or linebreaks.

See Also

Difficulty: ★☆☆ (easy)
Keywords: section, sectX, sect1, nesting sections

Problem

You need to know what the differences and advantages are of using a section over a sectX element.

Solution

The differences between section against sectX are depicted in Table 1.1, “Comparison Between section and sectX Elements”:

Table 1.1. Comparison Between section and sectX Elements
Issue section sectX
Nesting Level? Undefinied[a] Up to five levels (sect5)
Readability? Worse Better
Easy Relocation? Yes No, needs to be renamed
Renaming after relocation? No Yes

[a]See discussion.

Discussion

Apart from technical issues, using section or sect1 is in most cases a matter of taste. However, knowing some of the differences in Table 1.1 can be helpful to decide which is for your document the better element.

Nesting Level  If you have documents which goes further than level five, use the section element. This can be indefinitely nested. On the other side, if you want to restrict the level up to five, better use the sectX elements. You can, however, use DocBook's RELAX NG schema to customize it further (see next section).

Readability  This issue depends on how you edit your DocBook source code. If you edit it manually in your editor (in other words: without the aid of some kind of “WYSYWYG”), you can see and understand the level straight from the tag name when using sectX. Especially if you have lots of nested section this makes it a lot easier than section. However, modern XML editors can show the XPath where you are, so it may be negligible.

Relocation  If you have to change the structure a lot, using section elements make it a lot easier. When you use a sect2 element and this should become a sect1 element you have to rename it.

See Also

http://www.docbook.org/tdg51/en/html/ch05.html#ex.limitsdepth

Difficulty: ★☆☆ (easy)
Keywords: lists, itemizedlist, orderedlist, variablelist, bibliolist, calloutlist, glosslist, segmentedlist, simplelist, numeration

Problem

You want to know what list types are available in DocBook.

Solution

DocBook provides three basic lists which are used most often:

  • itemizedlist, for unordered lists (like ul in HTML)

  • orderedlist for numbered lists (like ol in HTML)

  • variablelist, for lists containing terms and their definition (like dl in HTML)

Additionally, for specific purposes, DocBook provides special lists (not explained in this topic):

  • bibliolist is a wrapper for bibliographic content. A bibliolist is usually inserted in section-like elements where a bibliography is not allowed.

  • calloutlist, a usually numbered list which points to a line in a listing

  • glosslist is a wrapper for glossary content. A glosslist is usually inserted in section-like elements where a glossary is not allowed.

  • segmentedlist is a list which can be used which have a one-to-one dependence with its title. A segmentedlist can be formatted in a number of ways (tabular or as a list block).

  • simplelist is an unordered list for single words or small phrases.

The previous lists are used to maintain semantic distinction.

Discussion

The list types orderedlist and itemizedlist are structural identical (except for its initial element) as you will see in the following subsections.

The variablelist is slightly different and contains the term element for its term.

Features of itemizedlist

An itemizedlist is a unordered list and can be written as shown in the following example:

Example 1.4. Unordered List with Three Entries
  1 <itemizedlist>
  2   <listitem>
        <para>The first entry</para>
  4   </listitem>
      <listitem>
  6     <para>The second entry</para>
      </listitem>
  8   <listitem>
        <para>The third entry</para>
 10   </listitem>
    </itemizedlist>

The itemizedlist list in DocBook uses by default a disc symbol (• solid circle). If you nest an itemizedlist, it will first start the disc (• solid circle) and uses a circle (○ open circle) and finally a square (■ solid square). If you nest your list deeper, the sequence is repeated. The hierarchy looks like this:

Level Shows as
1. • • •
2. ○ ○ ○
3. ■ ■ ■

The default bullet symbol can be overwritten with the mark attribute:

<itemizedlist mark="circle">

It is even possible to deviate from its default symbol in a listitem by using the overwrite attribute:

  1 <itemizedlist>
  2   <listitem>
        <para>The first entry</para>
  4   </listitem>
      <listitem overwrite="square">
  6     <para>The second entry</para>
      </listitem>
  8   <listitem>
        <para>The third entry</para>
 10   </listitem>
    </itemizedlist>
Features of orderedlist

An orderedlist can be written as shown in the following example:

Example 1.5. Numbered List with Three Entries
  1 <orderedlist>
  2   <listitem>
        <para>The first entry</para>
  4   </listitem>
      <listitem>
  6     <para>The second entry</para>
      </listitem>
  8   <listitem>
        <para>The third entry</para>
 10   </listitem>
    </orderedlist>

The orderedlist in DocBook numbers as arabic numbers by default. If you nest an orderedlist, it will be automatically numbered as shown in the following sequence:

Level Shows as
1. 1, 2, 3
2. a, b, c
3. i, ii, iii
4. A, B, C
5. I, II, III

The numbering style in an orderedlist can be changed with the numberation attribute. Allowed values are arabic, loweralpha, lowerroman, upperalpha, upperroman, arabicindic.

Features of variablelist

An variablelist, despite its confusing name, holds all sort of terms and their definition. It is not limited to variables only. The following example shows how to mark a variablelist.

Example 1.6. Definition List with Two Entries
  1 <variablelist>
  2   <varlistentry>
        <term>Hamburg</term>
  4     <listitem>
           <para>Town in the northern part of Germany</para>
  6     </listitem>
      </varlistentry>
  8   <varlistentry>
        <term>Nueremberg</term>
 10     <listitem>
           <para>Town in the south-eastern part of Germany</para>
 12     </listitem>
      </varlistentry>
 14 </variablelist>

A varlistentry can contain more than one term. How the terms are displayed depends usually on the output formats. By default, each term is printed on a separate line.

See Also

Difficulty: ★☆☆ (easy)
Keywords: remarks, show.comments

Problem

You want to insert comments or remarks in your document to enable or disable them in the output format.

Solution

For this purpose, DocBook provides a remark element. The following example shows how to use it:

Example 1.7. A Remark Inside a Paragraph
  1 <para>
  2 This is a small text.<remark>Add more content</remark>
    </para>

Discussion

To add comments in your document, there are two methods:

  • Use XML comments

  • Use DocBook’s remark element

XML comments can be placed almost everywhere in your XML document. It is a very common method to give yourself or others some hints. This can be done with XML comments like in this example:

<para>
This is a text <!-- Ohh, we should add more -->
</para>

However, XML comments has one drawback: They are suppressed during transformation. As such, they are unavailable in your output format and can not be displayed anymore. Usually, you do not want them to appear in your output.

On the contrary, by using the remark element, comments can be shown or suppressed whenever you want them. For example, if you write your document and put some remarks, you can show them to your contributors for review. After the document is ready to be published, leave the remark as they are but suppress the remark transformation.

To display or suppress your remarks, use the parameter show.comments. This parameter can appear either on the command line of your XSLT processor or in a customization layer. Any non-zero value shows your remarks whereas a value of zero suppress them.

When should you use XML comments and when remarks? The following table gives you a quick overview.

Table 1.2. Comparison XML Comments versus Remarks
Topic XML Comments Remarks
When to use it?

Comments which are only read by you

Comments which can and should be read by others

Where to place it?

Almost everywhere[a]

Restricted by the DocBook schema[b]

Can be displayed and suppressed? No, always suppressed Yes, by using the parameter show.comments

[a]An example where you cannot insert your XML comment is inside an attribute.

Difficulty: ★☆☆ (easy)
Keywords: cross references, internal link, xref

Problem

The problem explained.

Solution

The solution explained.

Discussion

Some discussion about the problem and solution.

See Also

Include URL or bibliographic references.

Difficulty: ★☆☆ (easy)
Keywords: quotes, typographic quotes

Problem

You want to use inline quotes in a consistent and language independant way.

Solution

Use the quote tag:

<para>This is an <quote>English quote</quote>.</para>

Discussion

When people need quotes, they usually write "this". However, from a typographical point of view, this is wrong. There are special start and end quotation characters. The more elegant way is to use “this”.

However, the open and close characters are language dependent. Each language has different quotation rules. German readers prefer „this“, French « this », and the Italians use «this».

Using quote markers directly has one disadvantages: if your text contains different languages you need to know how quotes are displayed in the respective language. Also it is easier and more consistent to leave this typographic detail to the DocBook stylesheets.

One nice thing with inserting quote is it can be adapted to a different language by using the xml:lang attribute:

<para>This is a <quote xml:lang="de">German quote</quote>.</para>

[3]To use XInclude with DocBook 5.x, use the docbookxi.rnc RELAX NG schema.

[4]In DocBook 4 use the ulink element

Chapter 2. Common Customizations

Some typical problems are independant from their target formats. This chapter gives you some information what falls into this category.

A lot of customizations can be shared between different output formats. As such, it is probably a good idea to think about how to structure and store your customizations before starting. The following directories are a good start, especially if you want to support different output formats:

  1 mycustomizations/
  2   +-- common/
      +-- fo/
  4   +-- html/
      +-- futher formats...

The common directory contains all the stylesheets which are not specific to any formats. On the contrary, fo, html, etc. contains the respective customizations for their target formats.

Furthermore, it is recommended to use the same file name than the original from the DocBook XSL stylesheets. This makes it easier to see, what changes can be expected within your files.

Difficulty: ★☆☆ (easy)
Keywords: fonts, SIL, Google Web Fonts, CTAN, Linux Libertine fonts, DejaVu fonts, Stix fonts

Problem

You need to find professional fonts, preferebly released under an open source license which can be used for print or Web formats.

Solution

There are some very good fonts which can be used freely. Most fonts are even released under the Open Font License or other free or open licenses. The following list is a small overview which is by no means complete (use also your favorite search enginge):

http://scripts.sil.org

SIL is a nonprofit organization for sustainable language development. One part is to “support the use of non-Roman and complex scripts in language development.SIL creates the Charis SIL, Doulos SIL, Gentium, Andika, and other typefaces. All fonts are released under the Open Font License (OFL). This license was specially created for fonts and was initiated by SIL

FIXME: Check!

http://www.google.com/webfonts

Google Web Fonts is a huge collection of open source fonts. They can be freely incorporated into your Web sites using CSS or can be downloaded and embedded in PDF.

http://www.tug.org/tetex/

The TeTeX distribution and CTAN contains also some high quality fonts, however, more aimed at the print business and not for the Web.

http://www.linuxlibertine.org

The Linux Libertine fonts are designed to be an alternative to the serif Times fonts. The Linux Libertine and the Linux Biolinum fonts are a collection of serif and sans serif fonts with the usual Latin, Greek, Cyrillic, and Hebrew glyphs. Additionally, the fonts contain ligatures, true small caps, old style numbers, proportional or monospaced numbers, true superscript and subscript, and much more. A monospace variant is currently designed.

http://dejavu-fonts.org

FIXME
The DejaVu font family are derived from the Bitstream Vera fonts. Due to license issues, the font has to be renamed. The fonts contain now lots of glyphs.

http://www.stixfonts.org

TBD

Discussion

Before you use a font, answer the following questions:

  • Supported Languages and Amount of Glyphs  Does your font support your language? Although modern fonts use Unicode thesedays, nevertheless your language might be not supported. Especially if you need “uncommon” languages or rarely used glyphs.

  • Missing Styles  Some fonts are published in only one style, usually regular. Such fonts makes it more difficult to universally adopt them in different scenarios where more styles (bold, italic, or a combination) are needed.

  • Font Formats  Modern fonts are usually Unicode fonts published as OTF or TTF format. Older fonts are mostly PostScript Type 1 fonts which have a limited amount of glphys (theoretically 256). PostScript fonts cannot be used on the Web.

  • Font Combinations  For a non-designer, it is generally easier to use a complete font family conisting of sans serif, serif and monospaced typefaces. The reason for this is these typefaces are made to fit together. It is much more difficult to select fonts which work aesthetically as it needs experiences.

  • Quality  This is a broad topic and it depends heavily where you want to use the font. Is it primarily used for Web content or only for print? Or both? Some fonts looks only good in a Web page, other work only for printed documents. Sometimes the Hinting (adjustment of a font to a certain resolution) may or may not be implemented.

Difficulty: ★★☆ (medium)
Keyword: customization layer

Problem

You want to write a customization layer for the DocBook XSL stylesheets, but you do not know how to do it.

Solution

A DocBook XSL customization layer comprise the following components:

  • A XSLT stylesheet skeletton with the start tag <xsl:stylesheet> and the end tag </xsl:stylesheet>

  • At least the namespaces for XSLT, DocBook 5, and your output format (for example, FO or XHTML).

  • A <xsl:import/> element to incoporate the base DocBook XSLT stylesheet.

  • Your customizations (parameters, variables, templates, or other imports).

How this can look is shown in the following listing.

Example 2.1. General Customization Layer
  1 <xsl:stylesheet version="1.0"
  2   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:d="http://docbook.org/ns/docbook">
  4   
      <xsl:import href="http://docbook.sourceforge.net/release/xsl-ns/current/FORMAT/docbook.xsl"/>
  6   
      <!-- Your customizations go here -->
  8   
    </xsl:stylesheet>

Discussion

Why not modify the original stylesheets? There are some profound reasons which speaks against such modifications:

  • Whenever you update your stylesheet, all your modifications are lost.

  • If you modify the original stylesheets directly you can not go back to the former output.

  • It is hard to distinguish between your customizations and the original one.

Refrain from editing the original stylesheets! Always write a customization layer.

Apart from the above, obvious reasons, the following list gives you some recommendations:

  • Insert common parameters or templates into a stylesheet which is included in your different customizations.

  • Structure your output formats in different directories as shown in Section 2.1, “Introduction”.

  • Name your main stylesheet docbook.xsl or chunk.xsl (HTML only).

  • If your customization grows, outsource your customization into several stylesheets and include them into your “main” stylesheet.

  • Name your files like the DocBook XSL stylesheets. For example, if you customize filename (an inline element) put it into the file inline.xsl.

An example how this can look like, is shown in Example 2.2, “Structure ”:

Example 2.2. Structure
  1 mycustomizations/
  2   +-- common/
          +-- common.xsl 1
  4   +-- fo/
          +-- docbook.xsl 2
  6       +-- inline.xsl  3
      +-- html/
  8       +-- docbook.xsl 4
          +-- chunk.xsl   5
 10       +-- inline.xsl  6

1  

Common customizations across different formats

2  

Main stylesheet for FO output; includes inline.xsl

3  

Contains all modifications for inline elements regarding the FO output.

4  

Main stylesheet for HTML output; includes inline.xsl

5  

Main stylesheet for HTML output; imports docbook.xsl

6  

Contains all modifications for inline elements regarding the FO output.

To use one of the customization layer with, for example, xsltproc, use:

xsltproc mycustomizations/html/docbook.xsl mydocbook.xml

See Also

http://www.sagehill.net/docbookxsl/CustomMethods.html#CustomizationLayer

Difficulty: ★☆☆ (easy)
Keywords: date and time, datetime, dbtimestamp, processing-instruction, context

Problem

You want to insert the current date, time, or both in your output format (for example, to show the date of creation).

Solution

Use the <?dbtimestamp?> processing instruction (PI). For example, integrate it into the pubdate to show the current publication date on the titlepage:

  1 <info>
  2   <!-- ... -->
      <pubdate><?dbtimestamp?></pubdate>
  4 </info>

Discussion

The above PI includes the date in its localized form, or in other words: the output depends on the current language. If you do not have set any language, the default is English (en_US) which is month/day/year. If you want to change the default format, use one of the two options:

  • Change the default format

  • Add pseudo-attributes

Changing the Default Format

Each language contains in its language files

add xref
the context datetime. The following code shows it for the English language file:

  1 <l:context name="datetime">
  2   <l:template name="format" text="m/d/Y"/>
    </l:context>

This is only useful, if you want to completely change the appearance of a date in your document.

Adding Pseudo-Attributes

The simpler method is to change the PI directly. Especially if you do not want to customize the date for the complete document or you want it change individually. Basically, add a pseudo-attribute[5] into the <?dbtimestamp?> PI. For example, if you want to insert only the year, add the format pseudo-attribute:

<?dbtimestamp format="Y"?>

More format-letters can be found in the reference page (see link at the See Also section).

See Also

Problem

You need to retrieve a title, but your current node is not title.

Solution

The DocBook XSL stylesheets offers the title.markup mode for this purpose. Usually, insert the following code in the appropriate place:

<xsl:apply-templates select="." mode="title.markup"/>

The xsl:apply-templates recursively finds the correct title, regardless where you currently are. It also looks into an info element, if necessary.

Discussion

To further elaborate why you should use the mode, let's assume you have this chapter title:

  1 <chapter>
  2    <title>Programming in Python</title>
       <!-- further substructure pruned -->
  4 </chapter>

Let's assume further, you have a template where you need the title of the enclosing section, chapter, etc. One solution simple, yet unfavorable solution could be coded like this:

  1 <xsl:template name="...">
  2    <xsl:value-of select="ancestor::d:title"/>
    </xsl:template>

This has several disadvantages:

  • The XPath does not consider a title inside an info element.

  • The xsl:value-of returns the string value. In most cases this is correct. However, if you have a quote inside title, the quote is not processed and you will not get any quotation marks.

Replacing xsl:value-of through the xsl:apply-templates ensures processing of child elements inside title.

See Also

Difficulty: ★☆☆ (easy)
Keywords: PI, processing instructions, pseudo-attributes

Problem

You need an own processing instruction (not one from the DocBook XSL stylesheets) to fine-tune your transformation.

Solution

The DocBook XSL stylesheet offers the pi-attribute template for this purpose. It expects a processing instruction node and a “pseudo-attribute” name. For example, the following processing instruction is given:

<?toms-html background-color="blue"?>

Call pi-attribute to extract the content of the pseudo-attribute name:

  1 <xsl:call-template name="pi-attribute">
  2   <xsl:with-param name="pis" select="processing-instruction('toms-html')"/>
      <xsl:with-param name="attribute" select="'background-color'"/>
  4 </xsl:call-template>

This gives you the result blue.

Discussion

Processing instructions (PIs) are usually needed for fine-tune your output formats. For example, to add page break information, background color, or other stylistic hints. PIs should not be used to insert data which should normally reside inside a DocBook element! As a general rule of thumb: Use PIs if you want provide layout specific information for your output format if there is no other method.

The following example use the PI <?toms-html?> which is included inside an para element to insert background color in HTML:[6]

  1. Invent a target name for your processing instruction. This name should be unique and must not conflict with existing PIs (like <?dbhtml?>, <?dbfo?>, etc.) For example, you could use your abbreviated name and the output format to distinguish it from other processing instructions.

  2. Insert your PI into a para which indicates a different background color:

      1 <para><?toms-html background-color="blue"?>
      2   ...
        </para>
  3. Create a customization layer as shown in Section 2.3, “Writing Customization Layers”.

  4. Customize the para template and add the following code to your customization layer. The customized template call pi-attribute with the relevant parameters. If no PI was set, apply the original template:

      1 <xsl:template match="d:para">
      2   <xsl:variable name="bg">     1
            <xsl:call-template name="pi-attribute">
      4       <xsl:with-param name="pis" select="processing-instruction('toms-html')"/>
              <xsl:with-param name="attribute" select="'background-color'"/>
      6     </xsl:call-template>
          </xsl:variable>
      8   <xsl:choose>
            <xsl:when test="$bg != ''">2   
     10       <div style="background-color:{$bg}">  3
                <xsl:apply-imports/>   4
     12       </div>
            </xsl:when>
     14     <xsl:otherwise>
              <xsl:apply-imports/>     4
     16     </xsl:otherwise>
          </xsl:choose>
     18 </xsl:template>

    1 

    Fill the variable bg with the result of pi-attribute. Note, the select only matches for PIs inside a para.

    2 

    Decide what to do when background color is found.

    3 

    Wrap our paragraph around div with the corresponding background-color inside a style attribute.

    4 

    Delegate the default handling to the original para template.

  5. Build your document with your customization layer.

The previous example recognizes a PI inside a para only. If you want to recognize also PIs before, use the following XPath in the select attribute of pi-attribute:

  1 ( processing-instruction('toms-html') | 
  2   dpreceding-sibling::processing-instruction('toms-html')[1] 
    )[last()]

If two PIs are available (one inside, another outside), the one which is located inside takes precedence.

See Also

Difficulty: ★☆☆ (easy)
Keywords: XPath, debugging

Problem

You need the path to your current node—the XPath—to output it as debugging information.

Solution

The DocBook XSL stylesheet offers the xpath.location template for this purpose. To output the current XPath, use the following procedure:

  1. Import the xpath.location template from the DocBook XSL stylesheets in your customization layer:

    <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/lib/lib.xsl"/>
  2. Add the following code in your template:

      1 <xsl:message>
      2   <xsl:text>Current XPath: </xsl:text>
          <xsl:call-template name="xpath.location"/>
      4 </xsl:message>

If you need the XPath for a different node, extend the previous code:

  1 <xsl:message>
  2   <xsl:text>Current XPath: </xsl:text>
      <xsl:call-template name="xpath.location">
  4     <xsl:with-param name="node" select="YOUR_XPath_Expression"/>
      </xsl:call-template>
  6 </xsl:message>

Discussion

Currently, the template in lib/lib.xsl is limited: it walks from the current node up to the root node and outputs just the element name. No namespace prefixes, no predicates. If you have a DocBook document with different namespaces, the original version does not help.

In Example 2.3, “Namespace-aware Output of an XPath”, the revised template recognizes namespaces and counts elements on the sibling axis.

Example 2.3. Namespace-aware Output of an XPath
  1 <xsl:stylesheet version="1.0"
  2   xmlns:n="urn:x-toms:ns:namespaces"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  4   exclude-result-prefixes="n">
      <namespaces xmlns="urn:x-toms:ns:namespaces">  1
  6     <ns prefix="d">http://docbook.org/ns/docbook</ns>
        <ns prefix="xi">http://www.w3.org/2001/XInclude</ns>
  8     <ns prefix="rdf">http://www.w3.org/1999/02/22-rdf-syntax-ns#</ns>
        <ns prefix="cc">http://creativecommons.org/ns#</ns>
 10     <ns prefix="svg">http://www.w3.org/2000/svg</ns>
      </namespaces>
 12   
      <xsl:variable name="nsnodes" select="document('')//n:namespaces/n:ns"/> 2
 14   
      <xsl:template name="xpath.location">
 16     <xsl:param name="node" select="."/>
        <xsl:param name="path" select="''"/>
 18     <xsl:param name="method">prefix</xsl:param>            3
      
 20     <xsl:variable name="next.path">
          <xsl:choose>                                         4
 22         <xsl:when test="$method = 'prefix' and $nsnodes[namespace-uri($node)]">
              <xsl:value-of select="concat($nsnodes[namespace-uri($node) = .]/@prefix, ':')"/>
 24         </xsl:when>
            <xsl:when test="$method = 'clark' and namespace-uri($node) != ''">
 26           <xsl:value-of select="concat('{', namespace-uri($node), '}')"/>
            </xsl:when>
 28       </xsl:choose>  
          <xsl:value-of select="local-name($node)"/>      
 30       <xsl:if test="generate-id($node) != generate-id(/*) and
                        count(../*[local-name()=local-name(current()) and
 32                              namespace-uri()=namespace-uri(current())]) > 1">  5
            <xsl:text>[</xsl:text>
 34         <xsl:value-of select="count(preceding-sibling::*
                              [local-name()=local-name(current()) and
 36                            namespace-uri()=namespace-uri(current())]) + 1"/>
          <xsl:text>]</xsl:text>
 38     </xsl:if>
          <xsl:if test="$path != ''">
 40         <xsl:text>/</xsl:text>
          </xsl:if>
 42       <xsl:value-of select="$path"/>
        </xsl:variable>
 44     
        <xsl:choose>
 46       <xsl:when test="$node/parent::*">
            <xsl:call-template name="xpath.location">
 48           <xsl:with-param name="node" select="$node/parent::*"/>
              <xsl:with-param name="path" select="$next.path"/>
 50         </xsl:call-template>
          </xsl:when>
 52       <xsl:otherwise>
            <xsl:value-of select="concat('/', $next.path)"/>
 54       </xsl:otherwise>
        </xsl:choose>
 56   </xsl:template>
      
 58 </xsl:stylesheet>

1 

Contains the list of namespaces and their prefixes

2 

Create a node set of all namespace to prefix mappings

3 

Defines the method how prefixes are displayed. You can choose between “prefix” and the Clark notation. The latter adds the namespace in curly brackets before the element name, but makes the whole XPath very verbose.

4 

Choose between the prefixed or Clark notation

5 

Checks, if we are not at the root node and there is more than one element with the same name and the same namespace. If this is true, we output a predicate where the current number is enclosed in squared brackets.

The template can output the XPath in two different notations:

Prefix (method="prefix", default)

Namespace nodes are abbreviated with a prefix. The prefix is definied in the namespaces element. A XPath to the first chapter inside a book looks like this:

/d:book/d:chapter[1]
Clark (method="clark")

Namespace nodes are printed with the full namespace URL. The namespace URL is definied in the namespaces element. A XPath to the first chapter inside a book looks like this:

/{http://docbook.org/ns/docbook}book/{http://docbook.org/ns/docbook}chapter[1]

Use Clark Notation For Debugging Purposes Only

The above notation is called the Clark notation, after James Clark, the editor of the XSLT 1.0 and XPath 1.0 specifications. However, this notation cannot be used in XSLT as it is not officially supported. Only use the prefixed version in this case. The Clark notation is just useful for debugging purposes when you want or need the full namespace URLs.

Be aware, the previous template is slower than the original version (it has to count a little bit more). For debugging purpose it is probably fine.

See Also

Difficulty: ★☆☆ (easy)
Keywords: l10n, translation, language files, local.l10n.xml, context, gentext, http://docbook.sourceforge.net/xmlns/l10n/1.0

Problem

You need a general solution to add localized text without hard-coding it into your stylesheet. Depending on the language, it should display the correct, translated text.

Solution

Use language files to add your text. Language files are the DocBook way to support several languages, all located under the common directory. Each file is in XML format and contains all your translated text as a key/value pair. For more complex settings and to group things, there are contexts. The key is never translated, it a constant and is only needed to find and retrieve the translated text.

To use a language file, proceed as follows:

Adding Your Own Localized Text
  1. Create a customization layer first as shown in Section 2.3, “Writing Customization Layers”.

  2. Add the parameter local.l10n.xml in your customization layer and point it to your language file (in this case, it is named myl10n.xml, but you can use any name you like):

    <xsl:param name="local.l10n.xml" select="document('myl10n.xml')"/>
  3. Open the myl10n.xml file and insert the following XML code as an example:

      1 <l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0"> 
      2   <l:l10n language="en">
            <l:gentext key="Authors" text="Authors"/>
      4     <l:gentext key="lastbuilt" text="Last built: "/>
          </l:l10n>
      6   <l:l10n language="de">
            <l:gentext key="Authors" text="Authoren"/>
      8     <l:gentext key="lastbuilt" text="Zuletzt gebaut: "/>
          </l:l10n>
     10 </l:i18n>

    The above code shows two language, English and German (marked in the language attribute). Furthermore, it contains two text entries for each language (“Authors” and “lastbuilt”).

  4. Call gentext in your template to retrieve the translated text:

      1 <xsl:call-template name="gentext">
      2   <xsl:with-param name="key" select="'Authors'"/>
        </xsl:call-template>

Discussion

The “gentext” method to insert language specific text is quite powerful, but not almighty. It helps you to keep translateable text in one place and avoids hard-coded locations in your stylesheets. If you need the translated text not for the default language (usually marked in the root element), but for a different language, use the xsl:with-param as shown:

  1 <xsl:call-template name="gentext">
  2   <xsl:with-param name="key" select="'Authors'"/>
      <xsl:with-param name="lang">de</xsl:with-param>
  4 </xsl:call-template>

See Also

http://www.sagehill.net/docbookxsl/Localizations.html

Difficulty: ★☆☆ (easy)
Keywords: language, l10n.language

Problem

You need the language of the current element or of your DocBook document.

Solution

Use the l10n.language template from common/l10n.xsl. It extracts the language attribute from the current context node or its ancestors:

  1 <xsl:variable name="language">
  2    <xsl:call-template name="l10n.language"/>
    </xsl:variable>

It returns a “normalized” string which is RFC1766 compliant.

If you need to change the current node, use the target parameter. For example, the following code extracts the language from the root element:

  1 <xsl:variable name="lang">
  2    <xsl:call-template name="l10n.language">
          <xsl:with-param name="target" select="/*"/>
  4    </xsl:call-template>
    </xsl:variable>

Discussion

Language information is stored in DocBook either in the lang (4.x) or xml:lang (>5.x) attributes. These attributes can be set on every DocBook element.

For example, if you have a chapter inside a book and want to extract the contents of the language attribute from this chapter, the following XPath expression gives you this information:

/book/chapter/@lang             DocBook 4.x
/db:book/db:chapter/@xml:lang   DocBook 5.x

Although the XPath expressions are simple, they have some drawbacks:

  • If no language attribute is set, no content can be retrieved. The used language is undefined.

  • There is no default language when a language is not set.

  • Language information can be written inconsistently, for example, en or EN.

  • The above expressions do not take into account the current context node. For example, the language in a foreignphrase element is usually different than a chapter or other parts of the document.

  • There are no checks for RFC compliance.

All the previous problems are considered by the l10n.language template. It searches for the nearest anchestor who contains a language attribute and returns its content. For example, consider the following structure:

  1 book xml:lang="en"
  2   chapter
        section
  4       para
            foreignphrase xml:lang="de"

If your current context is on the foreignphrase element, l10n.language will return de as language. However, if your context is on the para element, you will get en. The para, section, and chapter elements are children of book and therefore in the scope of the language attribute which gives you en. In the case no language is given, the template returns a default language from the l10n.gentext.default.language parameter (usually English).

Sometimes, returning only the language is not enough. The following table gives you some additional functions from common/l10n.xsl which can be useful for your code (Question marks(?) denote an optional parameter):

Table 2.1. Extracting Language Information
Template Description
attrnode = language.attribute(node="."?)
Useful for HTML. Returns an attribute node lang with the extracted language from the current node or one of its ancestors
attrnode = xml.language.attribute(node="."?)
Useful for XHTML. Returns an attribute node xml:lang with the extracted language from the current node or one of its ancestors
string = l10n.language.name(lang?)
Returns the English language name

See Also


[5]A pseudo-attribute looks like an XML attribute due to its similar syntax. However, it is not. A processing instruction can only contain text and no attributes. For more information about PIs, refer to the XML specification at http://www.w3.org/TR/REC-xml/#sec-pi.

[6]Usually, such a need would be solved through CSS and not PIs. However, this example shows just the principle so it is a perfect use case.

Chapter 3. Manipulating DocBook Document Structure

DocBook files can be created manually or by tools. Sometimes tools create a structure which is inconvenient for some reasons or you have legacy documents which contain the “wrong” structure. This chapter shows how to restructure your DocBook document in the way you want.

The methods described in this chapter are mostly XSLT solutions where you can find more or less in any XSLT book. Actually, some ideas origin from Sal Mangano´s excellent XSLT Cookbook. However, the solutions in this chapter are targeted exclusively on DocBook.

Most of these solutions are based on an identity transformation stylesheet which is shown in Example 3.1, “copy.xsl.

Example 3.1. copy.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  4   <xsl:template match="node() | @*">
        <xsl:copy>
  6       <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
  8   </xsl:template>  
    </xsl:stylesheet>

This simple stylesheet copies everything from the input document to the output document without any modifications. Although it seems quite useless at a first glance, it reveals its full power when combining it with customizations.

Difficulty: ★☆☆ (easy)
Keywords: pretty-print, xmlformat

Problem

Your file, be it autogenerated or somehow “mangled” is poorly indented and you want to get rid of this.

Solution

There are different solutions to this problem:

  • a “pretty-print” stylesheet

  • the XML parser xmllint

  • the xmlformat command

XML Parser xmllint

The XML parser xmllint offers the --format option to turn on indentation for each element.

xmllint --format XMLFILE
The Pretty-Print Stylesheet

The simplest stylesheet for indentation is shown in Example 3.2, “pretty.xsl. It relies on the copy.xsl stylesheet.

Example 3.2. pretty.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  4   xmlns="http://docbook.org/ns/docbook">
      
  6   <xsl:import href="copy.xsl"/>
      <xsl:output indent="yes"/>
  8 
      <xsl:strip-space elements="*"/>
 10   <xsl:preserve-space elements="d:screen d:literallayout
        d:programlisting d:address"/>
 12 </xsl:stylesheet>
Command xmlformat

The xmlformat tool is a Perl script which is available from the Web site http://www.kitebird.com/software/xmlformat/.

The tool distinguishes between block elements, inline elements, and verbatim elements (similar to DocBook). The difference between the types is the whitespace normalization.

Block elements typically begin with a new line and children are indented. Spacing before and after can be controlled too.

Inline elements occur in block elements. Normalization and line-wrapping occurs in regard to the enclosing block element.

Verbatim elements are not formatted at all. That means, the content of the input element is the same as the content of the output element, including whitespaces.

Discussion

The xmllint command with its --format option is the easiest candidate but lacks customization. This is useful if you do not have any other tools at hand and you prefer a quick and rough reformatting.

The pretty.xsl stylesheet is a pure XSLT solution. As such, it works on every platform which supports an XSLT processor. It is adaptable to your needs, but mixed content (like in para) is problematic.

The most adaptable method is xmlformat.

Difficulty: ★★☆ (medium)
Keywords: converting, DocBook 4, DocBook 5

Problem

You have a DocBook document in version 4.x, but you need 5.x.

Solution

Generally, the difference between version 4 and version 5 is minimal. Refer to the The Definitive Guide for detailed information what has been added, removed, or renamed.

One major change is that all DocBook 5.x elements are in the namespace http://docbook.org/ns/docbook. All these changes are taken into account by the db4-upgrade.xsl stylesheet in the DocBook Subversion repository. The URL is https://docbook.svn.sourceforge.net/svnroot/docbook/trunk/docbook/relaxng/tools/db4-upgrade.xsl. You just need to apply this stylesheet to your source DocBook document, for example:

xsltproc doc.xml db4-upgrade.xsl

Discussion

One disadvantage is that entities are not preserved. This is not a stylesheet issue as the entities are already resolved when the XSLT processor gets its hand on the source tree. The stylesheet never sees the entities.

The DocBook Transition Guide recommends the following steps (cited from there):

Preserving Entities between DocBook Conversion
  1. Open your existing document using your favorite editing tool. You must use a tool that is not XML-aware, or one that allows you to edit markup “in the raw”.

  2. Replace all occurrences of the entity references that you want to preserve with some unique string. For example, if you want to preserve &Product; references, you could replace them all with [[[Product]]] (assuming that the string [[[Product]]] doesn't occur anywhere else in your document).

  3. Copy the document type declaration of your document and save it some place. The document type declaration is everything from “<!DOCTYPE” to the closing “]>”.

  4. Perform the conversion with the db4-upgrade.xsl stylesheet.

  5. Open the new document using your favorite editing tool. Replace all occurrences of the unique string you used to save the entity references with the corresponding entity references.

  6. Paste the document type declaration that you saved onto the top of your new document.

  7. Remove the external identifier (the PUBLIC and/or SYSTEM keywords) from the document type declaration. A document that begins with:

      1 <!DOCTYPE book [
      2  <!ENTITY someEntity "some replacement text">
        ]>

    is perfectly well-formed. If you don't remove the references to the DTD, then your parser will likely try to validate against DocBook V4.0 and that's not going to work. Alternatively, you could refer to the DocBook V5.0 DTD.

See Also

Further information can be found in http://docbook.org/docs/howto/#convert4to5.

Difficulty: ★★☆ (medium)
Keywords: converting, DocBook 5, DocBook 4

Problem

You have a DocBook document in version 5.x, but you need 4.x.

Solution

Generally, the difference between version 4 and version 5 are minimal. Refer to the The Definitive Guide for detailed information what has been added, removed, or renamed.

In case you have or get DocBook 5 and need the former version, the following stylesheet which supports the core transformation might help:

Example 3.3. db5to4-core.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:d="http://docbook.org/ns/docbook"
  4   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xi="http://www.w3.org/2001/XInclude"
  6   xmlns:xlink="http://www.w3.org/1999/xlink"
      xmlns:html="http://www.w3.org/1999/xhtml"
  8   xmlns:exsl="http://exslt.org/common"
      exclude-result-prefixes="d xi xlink exsl html">
 10 
      <xsl:import href="copy.xsl"/>
 12   
      <xsl:output method="xml" indent="yes" 
 14     doctype-public="-//OASIS//DTD DocBook XML V4.5//EN"
        doctype-system="http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"/>
 16   <xsl:strip-space elements="*"/>
      <xsl:preserve-space 
 18     elements="d:screen d:programlisting d:literallayout xi:*"/>
      <xsl:variable name="inlines">abbrev accel acronym alt anchor
 20     annotation application author biblioref citation citebiblioid
        citerefentry citetitle classname code command computeroutput
 22     constant coref database date editor email emphasis envar errorcode
        errorname errortext errortype exceptionname filename firstterm
 24     footnote footnoteref foreignphrase function glossterm guibutton
        guiicon guilabel guimenu guimenuitem guisubmenu hardware indexterm
 26     initializer inlineequation inlinemediaobject interfacename jobtitle
        keycap keycode keycombo keysym link literal markup menuchoice
 28     methodname modifier mousebutton nonterminal olink ooclass
        ooexception oointerface option optional org orgname package
 30     parameter person personname phrase productname productnumber prompt
        property quote remark replaceable returnvalue shortcut subscript
 32     superscript symbol systemitem tag termdef token trademark type uri
        userinput varname wordasword xref</xsl:variable>
 34   
      <!-- Overwrite standard template and create elements without 
 36        a namespace node
      -->
 38   <xsl:template match="d:*">
        <xsl:element name="{local-name()}">
 40       <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
 42   </xsl:template>
        
 44   <xsl:template match="@xml:id|@xml:lang">
        <xsl:attribute name="{local-name()}">
 46       <xsl:apply-templates/>
        </xsl:attribute>
 48   </xsl:template>
      
 50   <!-- Suppress the following attributes: -->
      <xsl:template match="@annotations|@version"/>
 52   <xsl:template match="@xlink:*"/>
      
 54   <xsl:template match="@xlink:href">
        <xsl:choose>
 56       <xsl:when test="contains($inlines, local-name(..))">
            <ulink url="{.}" remap="{local-name(..)}">
 58           <xsl:value-of select=".."/>
            </ulink>
 60       </xsl:when>
          <xsl:otherwise>
 62         <xsl:message>@xlink:href could not be processed!
      parent element: <xsl:value-of select="local-name(..)"/>
 64         </xsl:message>
          </xsl:otherwise>
 66     </xsl:choose>
      </xsl:template>
 68   
      <xsl:template match="d:*[@xlink:href]">
 70     <xsl:choose>
          <xsl:when test="contains($inlines, local-name())">
 72         <ulink url="{@xlink:href}" remap="{local-name(.)}">
              <xsl:element name="{local-name()}">
 74             <xsl:apply-templates 
                  select="@*[local-name() != 'href' and
 76                          namespace-uri() != 'http://www.w3.org/1999/xlink']
                          |node()"/>
 78           </xsl:element>
            </ulink>
 80       </xsl:when>
          <xsl:otherwise>
 82         <xsl:element name="{local-name()}">
              <xsl:apply-templates 
 84             select="@*[local-name() != 'href' and
                           namespace-uri() != 'http://www.w3.org/1999/xlink']
 86                     |node()"/>
            </xsl:element>
 88       </xsl:otherwise>
        </xsl:choose>
 90   </xsl:template>
      
 92   <xsl:template match="d:link/@xlink:href">
        <xsl:attribute name="url">
 94       <xsl:value-of select="."/>
        </xsl:attribute>
 96   </xsl:template>
      
 98   <xsl:template match="d:link[@xlink:href]">
        <ulink>
100       <xsl:apply-templates select="@*|node()"/>
        </ulink>
102   </xsl:template>
      
104   <xsl:template match="d:link[@linkend]">
        <link>
106       <xsl:apply-templates select="@*|node()"/>
        </link>
108   </xsl:template>
      
110   <!-- Renamed DocBook elements -->
      <xsl:template match="d:personblurb">
112     <authorblurb>
          <xsl:apply-templates select="@*|node()"/>
114     </authorblurb>
      </xsl:template>
116   <xsl:template match="d:tag">
        <sgmltag>
118       <xsl:apply-templates select="@*|node()"/>
        </sgmltag>
120   </xsl:template>
      
122   <!-- New DocBook v5.1 and HTML elements, no mapping available -->
      <xsl:template match="d:acknowledgements|d:annotation|d:arc
124                        |d:cover
                           |d:definitions
126                        |d:extendedlink
                           |d:givenname
128                        |d:locator
                           |d:org|d:tocdiv
130                        |html:*">
        <xsl:message>Don't know how to transfer "<xsl:value-of
132       select="local-name()"/>" element into DocBook 4</xsl:message>
      </xsl:template>
134   
    </xsl:stylesheet>

Use your favorite XSLT processor to transform your documents.

Discussion

The stylesheet from Example 3.3, “db5to4-core.xsl imports the templates from copy.xsl using an identity transformation. That means, whatever is not specified gets copied. In most cases that is what you want—a DocBook 5 section element will be transformed into an equally named DocBook 4 section element without the namespace.

Where it gets difficult are the new elements which are introduced in DocBook 5. Whenever the stylesheet encounters those it will print a warning. These elements are not copied to the output stream. If you have one of those elements you need to customize the stylesheet yourself.

Another issue is the almost ubiquitary info element which can appear in structual and block elements. The above stylesheet does it wrong and copies any info element straight into the output stream. However, DocBook 4 has different element names for meta information in DocBook 5. If you have info elements in your document they have to be renamed, depending on the parent element:

  • Meta Information Inside Structural Elements  An info element inside a sect1 appends the suffix info to the name of its parent element and is renamed therefore as sect1info. This rule is applied for structural elements like book, chapter, and others.

  • Meta Information Inside Block Elements  An info element inside an example is renamed as blockinfo. This rule is applied for block elements like equation, figure, and others.

Apart from the renaming, the order of the renamed info element is crucial. Consider the following DocBook 5 structure:

  1 section
  2   title
      info

This structure has to be renamed and reorganized as follows:

  1 section
  2   sectioninfo
      title

As you can see, the title element appears now after the renamed info. All these issues are solved with the following additional stylesheet:

Example 3.4. db5to4-info.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  4   xmlns:d="http://docbook.org/ns/docbook"
      xmlns:xlink="http://www.w3.org/1999/xlink"
  6   xmlns:exsl="http://exslt.org/common"
      exclude-result-prefixes="d xlink exsl">
  8   
      <!-- Structural elements using info -->
 10   <xsl:template match="d:appendix[d:info]
                          |d:article[d:info]
 12                       |d:bibliography[d:info]
                          |d:book[d:info]
 14                       |d:chapter[d:info]
                          |d:colophon[d:info]
 16                       |d:equation[d:info]
                          |d:glossary[d:info]
 18                       |d:index[d:info]
                          |d:legalnotice[d:info]
 20                       |d:part[d:info]
                          |d:partintro[d:info]
 22                       |d:preface[d:info]
                          |d:reference[d:info]
 24                       |d:refsect1[d:info]
                          |d:refsect2[d:info]
 26                       |d:refsect3[d:info]
                          |d:refsection[d:info]
 28                       |d:refsynopsisdiv[d:info]
                          |d:sect1[d:info]
 30                       |d:sect2[d:info]
                          |d:sect3[d:info]
 32                       |d:sect4[d:info]
                          |d:sect5[d:info]
 34                       |d:section[d:info]
                          |d:set[d:info]
 36                       |d:setindex[d:info]">
        <!-- Change order of info and title  -->
 38     <xsl:element name="{local-name()}">
          <xsl:apply-templates select="@*"/>
 40       <xsl:apply-templates select="d:title/preceding-sibling::processing-instruction()
                                       |d:title/preceding-sibling::comment()"/>
 42       <xsl:apply-templates select="d:info"/>
          <xsl:apply-templates select="d:title"/>
 44       <!-- Process the rest -->
          <xsl:apply-templates select="d:info/following-sibling::node()"/>
 46     </xsl:element>
      </xsl:template>
 48   
      <!-- Block elements using info -->
 50   <xsl:template match="d:bibliolist[d:info]
                          |d:blockquote[d:info]
 52                       |d:equation[d:info]
                          |d:example[d:info]
 54                       |d:figure[d:info]
                          |d:glosslist[d:info]
 56                       |d:informalequation[d:info]
                          |d:informalexample[d:info]
 58                       |d:informalfigure[d:info]
                          |d:informaltable[d:info]
 60                       |d:itemizedlist[d:info]
                          |d:legalnotice[d:info]
 62                       |d:msgset[d:info]
                          |d:orderedlist[d:info]
 64                       |d:procedure[d:info]
                          |d:qandadiv[d:info]
 66                       |d:qandaentry[d:info]
                          |d:qandaset[d:info]
 68                       |d:table[d:info]
                          |d:task[d:info]
 70                       |d:taskprerequisites[d:info]
                          |d:taskrelated[d:info]
 72                       |d:tasksummary[d:info]
                          |d:variablelist[d:info]">
 74     <xsl:element name="{local-name()}">
          <xsl:apply-templates select="@*"/>
 76       <xsl:apply-templates select="d:title/preceding-sibling::processing-instruction()
                                       |d:title/preceding-sibling::comment()"/>
 78       <xsl:apply-templates select="d:info">
            <xsl:with-param name="infoname">block</xsl:with-param>
 80       </xsl:apply-templates>
          <xsl:apply-templates select="d:title|
 82                                    d:title/following-sibling::processing-instruction()[1]
                                       |d:title/following-sibling::comment()[1]"/>
 84       
          <!-- Process the rest -->
 86       <xsl:apply-templates select="d:info/following-sibling::node()"/>
        </xsl:element>
 88   </xsl:template>
    
 90   <!-- Suppress other info elements who has no direct mapping -->
      <xsl:template match="d:*[d:info]"/>
 92   
      <xsl:template match="d:info">
 94     <xsl:param name="infoname" select="local-name(..)"/>
        <xsl:variable name="rtf-node">
 96       <xsl:element name="{$infoname}info">
          <xsl:apply-templates select="@*|node()"/>
 98     </xsl:element>
        </xsl:variable>
100     <xsl:choose>
          <xsl:when test="count(exsl:node-set($rtf-node)/*/*) > 0">
102         <xsl:copy-of select="$rtf-node"/>
          </xsl:when>
104       <xsl:otherwise><!-- Don't copy, it's empty --></xsl:otherwise>
        </xsl:choose>
106   </xsl:template>
    </xsl:stylesheet>

To combine both, use the following stylesheet:

Example 3.5. db5to4-withinfo.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  4   xmlns:d="http://docbook.org/ns/docbook">
    
  6   <xsl:import href="db5to4-core.xsl"/>
      <xsl:import href="db5to4-info.xsl"/>
  8   
      <xsl:output method="xml" indent="yes" 
 10     doctype-public="-//OASIS//DTD DocBook XML V4.5//EN"
        doctype-system="http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"/>
 12 </xsl:stylesheet>

The above stylesheets were separated between a core functionality (db5to4-core.xsl) with additional info element handling (db5to4-info.xsl). In most cases you will use the stylesheet db5to4-withinfo.xsl, but if you want to implement a different info handling you can. In Example 3.5, “db5to4-withinfo.xsl just replace the line with importing db5to4-info.xsl with your own implementation.

Difficulty: ★★☆ (medium)
Keywords: splitting, exsl:document

Problem

You have a big DocBook document, like a book, and you want to split each chapter, appendix etc. into a separate file.

Solution

There are two solutions to this problems:

  • Apply a XSLT stylesheet which uses an extension element like exsl:document

  • Run the dbautosplit command

Splitting with XSLT

The stylesheet in Example 3.6, “dbsplit.xsl uses extension elements to create separate documents from the main output. It uses code from html/chunk-code.xsl.

Example 3.6. dbsplit.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <!DOCTYPE xsl:stylesheet 
    [
  4  <!ENTITY db "http://docbook.sourceforge.net/release/xsl-ns/current"> 
    ]>
  6 <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  8   xmlns:d="http://docbook.org/ns/docbook"
      xmlns:exsl="http://exslt.org/common"
 10   xmlns:xi="http://www.w3.org/2001/XInclude"
      extension-element-prefixes="exsl">
 12 
      <xsl:import href="chunker.xsl"/>
 14   <xsl:import href="copy.xsl"/>
      <xsl:output indent="yes"/>
 16 
    
 18   <xsl:param name="base.dir" select="'out/'"/>
      <xsl:param name="use.id.as.filename" select="0"/>
 20   <xsl:param name="rootid"/>
    
 22   <xsl:param name="dbsplit.root.filename">Index</xsl:param>
      <xsl:param name="dbsplit.ext">.xml</xsl:param>
 24   <xsl:param name="dbsplit.chunk.depth" select="2"/>
    
 26   <xsl:template name="object.id">
        <xsl:param name="object" select="."/>
 28     <xsl:choose>
          <xsl:when test="$object/@id">
 30         <xsl:value-of select="$object/@id"/>
          </xsl:when>
 32       <xsl:when test="$object/@xml:id">
            <xsl:value-of select="$object/@xml:id"/>
 34       </xsl:when>
          <xsl:otherwise>
 36         <xsl:value-of select="generate-id($object)"/>
          </xsl:otherwise>
 38     </xsl:choose>
      </xsl:template>
 40 
      <xsl:template match="*" mode="recursive-chunk-filename">
 42     <xsl:param name="recursive" select="false()"/>
        <xsl:variable name="filename">
 44       <xsl:choose>
            <!-- if this is the root element, use the dbsplit.root.filename -->
 46         <xsl:when test="not(parent::*) and $dbsplit.root.filename != ''">
              <xsl:value-of select="$dbsplit.root.filename"/>
 48           <xsl:value-of select="$dbsplit.ext"/>
            </xsl:when>
 50         <!-- Special case -->
            <xsl:when
 52           test="self::d:legalnotice and not($generate.legalnotice.link = 0)">
              <xsl:choose>
 54             <xsl:when
                  test="(@id or @xml:id) and not($use.id.as.filename = 0)">
 56               <!-- * if this legalnotice has an ID, then go ahead and use -->
                  <!-- * just the value of that ID as the basename for the file -->
 58               <!-- * (that is, without prepending an "ln-" too it) -->
                  <xsl:value-of select="(@id|@xml:id)[1]"/>
 60               <xsl:value-of select="$dbsplit.ext"/>
                </xsl:when>
 62             <xsl:otherwise>
                  <!-- * otherwise, if this legalnotice does not have an ID, -->
 64               <!-- * then we generate an ID... -->
                  <xsl:variable name="id">
 66                 <xsl:call-template name="object.id"/>
                  </xsl:variable>
 68               <!-- * ...and then we take that generated ID, prepend an -->
                  <!-- * "ln-" to it, and use that as the basename for the file -->
 70               <xsl:value-of select="concat('ln-',$id,$dbsplit.ext)"/>
                </xsl:otherwise>
 72           </xsl:choose>
            </xsl:when>
 74         <!-- if there's no dbhtml filename, and if we're to use IDs as -->
            <!-- filenames, then use the ID to generate the filename. -->
 76         <xsl:when test="(@id or @xml:id) and $use.id.as.filename != 0">
              <xsl:value-of select="(@id|@xml:id)[1]"/>
 78           <xsl:value-of select="$dbsplit.ext"/>
            </xsl:when>
 80         <xsl:otherwise/>
          </xsl:choose>
 82     </xsl:variable>
    
 84     <xsl:choose>
          <xsl:when test="not($recursive) and $filename != ''">
 86         <!-- if this chunk has an explicit name, use it -->
            <xsl:value-of select="$filename"/>
 88       </xsl:when>
    
 90       <xsl:when test="self::d:set">
            <xsl:value-of select="$dbsplit.root.filename"/>
 92         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
 94         </xsl:if>
          </xsl:when>
 96 
          <xsl:when test="self::d:book">
 98         <xsl:text>bk</xsl:text>
            <xsl:number level="any" format="01"/>
100         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
102         </xsl:if>
          </xsl:when>
104 
          <xsl:when test="self::d:article">
106         <xsl:if test="/d:set">
              <!-- in a set, make sure we inherit the right book info... -->
108           <xsl:apply-templates mode="recursive-chunk-filename"
                select="parent::*">
110             <xsl:with-param name="recursive" select="true()"/>
              </xsl:apply-templates>
112         </xsl:if>
    
114         <xsl:text>ar</xsl:text>
            <xsl:number level="any" format="01" from="d:book"/>
116         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
118         </xsl:if>
          </xsl:when>
120 
          <xsl:when test="self::d:preface">
122         <xsl:if test="/d:set">
              <!-- in a set, make sure we inherit the right book info... -->
124           <xsl:apply-templates mode="recursive-chunk-filename"
                select="parent::*">
126             <xsl:with-param name="recursive" select="true()"/>
              </xsl:apply-templates>
128         </xsl:if>
    
130         <xsl:text>pr</xsl:text>
            <xsl:number level="any" format="01" from="d:book"/>
132         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
134         </xsl:if>
          </xsl:when>
136 
          <xsl:when test="self::d:chapter">
138         <xsl:if test="/d:set">
              <!-- in a set, make sure we inherit the right book info... -->
140           <xsl:apply-templates mode="recursive-chunk-filename"
                select="parent::*">
142             <xsl:with-param name="recursive" select="true()"/>
              </xsl:apply-templates>
144         </xsl:if>
    
146         <xsl:text>ch</xsl:text>
            <xsl:number level="any" format="01" from="d:book"/>
148         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
150         </xsl:if>
          </xsl:when>
152 
          <xsl:when test="self::d:appendix">
154         <xsl:if test="/d:set">
              <!-- in a set, make sure we inherit the right book info... -->
156           <xsl:apply-templates mode="recursive-chunk-filename"
                select="parent::*">
158             <xsl:with-param name="recursive" select="true()"/>
              </xsl:apply-templates>
160         </xsl:if>
    
162         <xsl:text>ap</xsl:text>
            <xsl:number level="any" format="a" from="d:book"/>
164         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
166         </xsl:if>
          </xsl:when>
168 
          <xsl:when test="self::d:part">
170         <xsl:choose>
              <xsl:when test="/d:set">
172             <!-- in a set, make sure we inherit the right book info... -->
                <xsl:apply-templates mode="recursive-chunk-filename"
174               select="parent::*">
                  <xsl:with-param name="recursive" select="true()"/>
176             </xsl:apply-templates>
              </xsl:when>
178           <xsl:otherwise> </xsl:otherwise>
            </xsl:choose>
180 
            <xsl:text>pt</xsl:text>
182         <xsl:number level="any" format="01" from="d:book"/>
            <xsl:if test="not($recursive)">
184           <xsl:value-of select="$dbsplit.ext"/>
            </xsl:if>
186       </xsl:when>
    
188       <xsl:when test="self::d:reference">
            <xsl:choose>
190           <xsl:when test="/d:set">
                <!-- in a set, make sure we inherit the right book info... -->
192             <xsl:apply-templates mode="recursive-chunk-filename"
                  select="parent::*">
194               <xsl:with-param name="recursive" select="true()"/>
                </xsl:apply-templates>
196           </xsl:when>
              <xsl:otherwise> </xsl:otherwise>
198         </xsl:choose>
    
200         <xsl:text>rn</xsl:text>
            <xsl:number level="any" format="01" from="d:book"/>
202         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
204         </xsl:if>
          </xsl:when>
206 
          <xsl:when test="self::d:refentry">
208         <xsl:choose>
              <xsl:when test="parent::d:reference">
210             <xsl:apply-templates mode="recursive-chunk-filename"
                  select="parent::*">
212               <xsl:with-param name="recursive" select="true()"/>
                </xsl:apply-templates>
214           </xsl:when>
              <xsl:otherwise>
216             <xsl:if test="/d:set">
                  <!-- in a set, make sure we inherit the right book info... -->
218               <xsl:apply-templates mode="recursive-chunk-filename"
                    select="parent::*">
220                 <xsl:with-param name="recursive" select="true()"/>
                  </xsl:apply-templates>
222             </xsl:if>
              </xsl:otherwise>
224         </xsl:choose>
    
226         <xsl:text>re</xsl:text>
            <xsl:number level="any" format="01" from="d:book"/>
228         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
230         </xsl:if>
          </xsl:when>
232 
          <xsl:when test="self::d:colophon">
234         <xsl:choose>
              <xsl:when test="/d:set">
236             <!-- in a set, make sure we inherit the right book info... -->
                <xsl:apply-templates mode="recursive-chunk-filename"
238               select="parent::*">
                  <xsl:with-param name="recursive" select="true()"/>
240             </xsl:apply-templates>
              </xsl:when>
242           <xsl:otherwise> </xsl:otherwise>
            </xsl:choose>
244 
            <xsl:text>co</xsl:text>
246         <xsl:number level="any" format="01" from="d:book"/>
            <xsl:if test="not($recursive)">
248           <xsl:value-of select="$dbsplit.ext"/>
            </xsl:if>
250       </xsl:when>
    
252       <xsl:when test="self::d:sect1 or self::d:sect2 or self::d:sect3 or 
                          self::d:sect4 or self::d:sect5 or self::d:section">
254         <xsl:apply-templates mode="recursive-chunk-filename"
              select="parent::*">
256           <xsl:with-param name="recursive" select="true()"/>
            </xsl:apply-templates>
258         <xsl:text>s</xsl:text>
            <xsl:number format="01"/>
260         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
262         </xsl:if>
          </xsl:when>
264 
          <xsl:when test="self::d:bibliography">
266         <xsl:choose>
              <xsl:when test="/d:set">
268             <!-- in a set, make sure we inherit the right book info... -->
                <xsl:apply-templates mode="recursive-chunk-filename"
270               select="parent::*">
                  <xsl:with-param name="recursive" select="true()"/>
272             </xsl:apply-templates>
              </xsl:when>
274           <xsl:otherwise> </xsl:otherwise>
            </xsl:choose>
276 
            <xsl:text>bi</xsl:text>
278         <xsl:number level="any" format="01" from="d:book"/>
            <xsl:if test="not($recursive)">
280           <xsl:value-of select="$dbsplit.ext"/>
            </xsl:if>
282       </xsl:when>
    
284       <xsl:when test="self::d:glossary">
            <xsl:choose>
286           <xsl:when test="/d:set">
                <!-- in a set, make sure we inherit the right book info... -->
288             <xsl:apply-templates mode="recursive-chunk-filename"
                  select="parent::*">
290               <xsl:with-param name="recursive" select="true()"/>
                </xsl:apply-templates>
292           </xsl:when>
              <xsl:otherwise> </xsl:otherwise>
294         </xsl:choose>
    
296         <xsl:text>go</xsl:text>
            <xsl:number level="any" format="01" from="d:book"/>
298         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
300         </xsl:if>
          </xsl:when>
302 
          <xsl:when test="self::d:index">
304         <xsl:choose>
              <xsl:when test="/d:set">
306             <!-- in a set, make sure we inherit the right book info... -->
                <xsl:apply-templates mode="recursive-chunk-filename"
308               select="parent::*">
                  <xsl:with-param name="recursive" select="true()"/>
310             </xsl:apply-templates>
              </xsl:when>
312           <xsl:otherwise> </xsl:otherwise>
            </xsl:choose>
314 
            <xsl:text>ix</xsl:text>
316         <xsl:number level="any" format="01" from="d:book"/>
            <xsl:if test="not($recursive)">
318           <xsl:value-of select="$dbsplit.ext"/>
            </xsl:if>
320       </xsl:when>
    
322       <xsl:when test="self::d:setindex">
            <xsl:text>si</xsl:text>
324         <xsl:number level="any" format="01" from="d:set"/>
            <xsl:if test="not($recursive)">
326           <xsl:value-of select="$dbsplit.ext"/>
            </xsl:if>
328       </xsl:when>
    
330       <xsl:otherwise>
            <xsl:text>chunk-filename-error-</xsl:text>
332         <xsl:value-of select="name(.)"/>
            <xsl:number level="any" format="01" from="d:set"/>
334         <xsl:if test="not($recursive)">
              <xsl:value-of select="$dbsplit.ext"/>
336         </xsl:if>
          </xsl:otherwise>
338     </xsl:choose>
      </xsl:template>
340 
      <xsl:template name="generate-filename">
342     <xsl:apply-templates select="." mode="recursive-chunk-filename"/>
      </xsl:template>
344 
      <xsl:template name="generate-content">
346     <xsl:variable name="filename">
          <xsl:call-template name="make-relative-filename">
348         <xsl:with-param name="base.dir" select="$base.dir"/>
            <xsl:with-param name="base.name">
350            <xsl:call-template name="generate-filename"/>
            </xsl:with-param>
352       </xsl:call-template>
        </xsl:variable>
354     <xsl:variable name="depth" select="count(ancestor::*)"/>
        
356     <!--<xsl:message>generate-content:
          name: <xsl:value-of select="name()"/>
358       filename: <xsl:value-of select="$filename"/>
          depth: <xsl:value-of select="$depth"/>
360       test: <xsl:value-of select="$depth >= $dbsplit.chunk.depth"/>
        </xsl:message>-->
362     
        <xsl:choose>
364       <xsl:when test="$depth &lt;= $dbsplit.chunk.depth">
            <xi:include href="{$filename}"/>
366         <xsl:call-template name="write.xml.chunk">
              <xsl:with-param name="filename" select="$filename"/>
368           <xsl:with-param name="content">
                <xsl:copy-of select="preceding-sibling::processing-instruction()|
370                                  preceding-sibling::comment()"/>
                <xsl:copy>
372               <xsl:apply-templates/>
                </xsl:copy>
374           </xsl:with-param>
            </xsl:call-template>
376       </xsl:when>
          <xsl:otherwise>
378         <xsl:copy>
              <xsl:apply-templates/>
380         </xsl:copy>
          </xsl:otherwise>
382     </xsl:choose>
      </xsl:template>
384 
      <xsl:template
386     match="d:acknowledgements|d:appendix|d:article|
               d:bibliography|
388            d:chapter|d:colophon|d:dedication|d:glossary|
               d:part|d:preface|d:reference|d:topic|
390            d:sect1|d:section[not(parent::d:section)]">
        <xsl:call-template name="generate-content"/>
392   </xsl:template>
    
394 </xsl:stylesheet>

The chunker.xsl file is more or less a stripped down version of the html/chunker.xsl file from the DocBook XSL stylesheets. It is used to create processor independent writing of our XML chunks. The file was integrated into dbsplit.xsl to make it more independent from the DocBook XSL stylesheets.

Example 3.7. chunker.xsl
  1 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  2   xmlns:saxon="http://icl.com/saxon"
      xmlns:lxslt="http://xml.apache.org/xslt"
  4   xmlns:redirect="http://xml.apache.org/xalan/redirect"
      xmlns:exsl="http://exslt.org/common"
  6   xmlns="http://www.w3.org/1999/xhtml" version="1.0"
      exclude-result-prefixes="saxon lxslt redirect exsl"
  8   extension-element-prefixes="saxon redirect lxslt exsl">
    
 10   <xsl:param name="chunker.output.method" select="'xml'"/>
      <xsl:param name="chunker.output.encoding" select="'UTF-8'"/>
 12   <xsl:param name="chunker.output.indent" select="'no'"/>
      <xsl:param name="chunker.output.omit-xml-declaration" select="'no'"/>
 14   <xsl:param name="chunker.output.standalone" select="'no'"/>
      <xsl:param name="chunker.output.doctype-public" select="''"/>
 16   <xsl:param name="chunker.output.doctype-system" select="''"/>
      <xsl:param name="chunker.output.media-type" select="''"/>
 18   <xsl:param name="chunker.output.cdata-section-elements" select="''"/>
      <xsl:param name="chunker.output.quiet" select="0"/>
 20 
      <xsl:param name="saxon.character.representation"
 22     select="'entity;decimal'"/>
    
 24   <xsl:template name="make-relative-filename">
        <xsl:param name="base.dir" select="'./'"/>
 26     <xsl:param name="base.name" select="''"/>
    
 28     <xsl:choose>
          <!-- put Saxon first to work around a bug in libxslt -->
 30       <xsl:when test="element-available('saxon:output')">
            <!-- Saxon doesn't make the chunks relative -->
 32         <xsl:value-of select="concat($base.dir,$base.name)"/>
          </xsl:when>
 34       <xsl:when test="element-available('exsl:document')">
            <!-- EXSL document does make the chunks relative, I think -->
 36         <xsl:choose>
              <xsl:when test="count(parent::*) = 0">
 38             <xsl:value-of select="concat($base.dir,$base.name)"/>
              </xsl:when>
 40           <xsl:otherwise>
                <xsl:value-of select="$base.name"/>
 42           </xsl:otherwise>
            </xsl:choose>
 44       </xsl:when>
          <xsl:when test="element-available('redirect:write')">
 46         <!-- Xalan doesn't make the chunks relative -->
            <xsl:value-of select="concat($base.dir,$base.name)"/>
 48       </xsl:when>
          <xsl:otherwise>
 50         <xsl:message terminate="yes">
              <xsl:text>Don't know how to chunk with </xsl:text>
 52           <xsl:value-of select="system-property('xsl:vendor')"/>
            </xsl:message>
 54       </xsl:otherwise>
        </xsl:choose>
 56   </xsl:template>
    
 58   <xsl:template name="write.chunk">
        <xsl:param name="filename" select="''"/>
 60     <xsl:param name="quiet" select="$chunker.output.quiet"/>
        <xsl:param name="suppress-context-node-name" select="0"/>
 62     <xsl:param name="message-prolog"/>
        <xsl:param name="message-epilog"/>
 64 
        <xsl:param name="method" select="$chunker.output.method"/>
 66     <xsl:param name="encoding" select="$chunker.output.encoding"/>
        <xsl:param name="indent" select="$chunker.output.indent"/>
 68     <xsl:param name="omit-xml-declaration"
          select="$chunker.output.omit-xml-declaration"/>
 70     <xsl:param name="standalone" select="$chunker.output.standalone"/>
        <xsl:param name="doctype-public"
 72       select="$chunker.output.doctype-public"/>
        <xsl:param name="doctype-system"
 74       select="$chunker.output.doctype-system"/>
        <xsl:param name="media-type" select="$chunker.output.media-type"/>
 76     <xsl:param name="cdata-section-elements"
          select="$chunker.output.cdata-section-elements"/>
 78 
        <xsl:param name="content"/>
 80 
        <xsl:if test="$quiet = 0">
 82       <xsl:message>
            <xsl:if test="not($message-prolog = '')">
 84           <xsl:value-of select="$message-prolog"/>
            </xsl:if>
 86         <xsl:text>Writing </xsl:text>
            <xsl:value-of select="$filename"/>
 88         <xsl:if test="name(.) != '' and $suppress-context-node-name = 0">
              <xsl:text> for </xsl:text>
 90           <xsl:value-of select="name(.)"/>
              <xsl:if test="@id or @xml:id">
 92             <xsl:text>(</xsl:text>
                <xsl:value-of select="(@id|@xml:id)[1]"/>
 94             <xsl:text>)</xsl:text>
              </xsl:if>
 96         </xsl:if>
            <xsl:if test="not($message-epilog = '')">
 98           <xsl:value-of select="$message-epilog"/>
            </xsl:if>
100       </xsl:message>
        </xsl:if>
102 
        <xsl:choose>
104       <xsl:when test="element-available('exsl:document')">
            <xsl:choose>
106           <!-- Handle the permutations ... -->
              <xsl:when test="$media-type != ''">
108             <xsl:choose>
                  <xsl:when
110                 test="$doctype-public != '' and $doctype-system != ''">
                    <exsl:document href="{$filename}" method="{$method}"
112                   encoding="{$encoding}" indent="{$indent}"
                      omit-xml-declaration="{$omit-xml-declaration}"
114                   cdata-section-elements="{$cdata-section-elements}"
                      media-type="{$media-type}"
116                   doctype-public="{$doctype-public}"
                      doctype-system="{$doctype-system}"
118                   standalone="{$standalone}">
                      <xsl:copy-of select="$content"/>
120                 </exsl:document>
                  </xsl:when>
122               <xsl:when
                    test="$doctype-public != '' and $doctype-system = ''">
124                 <exsl:document href="{$filename}" method="{$method}"
                      encoding="{$encoding}" indent="{$indent}"
126                   omit-xml-declaration="{$omit-xml-declaration}"
                      cdata-section-elements="{$cdata-section-elements}"
128                   media-type="{$media-type}"
                      doctype-public="{$doctype-public}"
130                   standalone="{$standalone}">
                      <xsl:copy-of select="$content"/>
132                 </exsl:document>
                  </xsl:when>
134               <xsl:when
                    test="$doctype-public = '' and $doctype-system != ''">
136                 <exsl:document href="{$filename}" method="{$method}"
                      encoding="{$encoding}" indent="{$indent}"
138                   omit-xml-declaration="{$omit-xml-declaration}"
                      cdata-section-elements="{$cdata-section-elements}"
140                   media-type="{$media-type}"
                      doctype-system="{$doctype-system}"
142                   standalone="{$standalone}">
                      <xsl:copy-of select="$content"/>
144                 </exsl:document>
                  </xsl:when>
146               <xsl:otherwise>
                    <!-- $doctype-public = '' and $doctype-system = ''"> -->
148                 <exsl:document href="{$filename}" method="{$method}"
                      encoding="{$encoding}" indent="{$indent}"
150                   omit-xml-declaration="{$omit-xml-declaration}"
                      cdata-section-elements="{$cdata-section-elements}"
152                   media-type="{$media-type}" standalone="{$standalone}">
                      <xsl:copy-of select="$content"/>
154                 </exsl:document>
                  </xsl:otherwise>
156             </xsl:choose>
              </xsl:when>
158           <xsl:otherwise>
                <xsl:choose>
160               <xsl:when
                    test="$doctype-public != '' and $doctype-system != ''">
162                 <exsl:document href="{$filename}" method="{$method}"
                      encoding="{$encoding}" indent="{$indent}"
164                   omit-xml-declaration="{$omit-xml-declaration}"
                      cdata-section-elements="{$cdata-section-elements}"
166                   doctype-public="{$doctype-public}"
                      doctype-system="{$doctype-system}"
168                   standalone="{$standalone}">
                      <xsl:copy-of select="$content"/>
170                 </exsl:document>
                  </xsl:when>
172               <xsl:when
                    test="$doctype-public != '' and $doctype-system = ''">
174                 <exsl:document href="{$filename}" method="{$method}"
                      encoding="{$encoding}" indent="{$indent}"
176                   omit-xml-declaration="{$omit-xml-declaration}"
                      cdata-section-elements="{$cdata-section-elements}"
178                   doctype-public="{$doctype-public}"
                      standalone="{$standalone}">
180                   <xsl:copy-of select="$content"/>
                    </exsl:document>
182               </xsl:when>
                  <xsl:when
184                 test="$doctype-public = '' and $doctype-system != ''">
                    <exsl:document href="{$filename}" method="{$method}"
186                   encoding="{$encoding}" indent="{$indent}"
                      omit-xml-declaration="{$omit-xml-declaration}"
188                   cdata-section-elements="{$cdata-section-elements}"
                      doctype-system="{$doctype-system}"
190                   standalone="{$standalone}">
                      <xsl:copy-of select="$content"/>
192                 </exsl:document>
                  </xsl:when>
194               <xsl:otherwise>
                    <!-- $doctype-public = '' and $doctype-system = ''"> -->
196                 <exsl:document href="{$filename}" method="{$method}"
                      encoding="{$encoding}" indent="{$indent}"
198                   omit-xml-declaration="{$omit-xml-declaration}"
                      cdata-section-elements="{$cdata-section-elements}"
200                   standalone="{$standalone}">
                      <xsl:copy-of select="$content"/>
202                 </exsl:document>
                  </xsl:otherwise>
204             </xsl:choose>
              </xsl:otherwise>
206         </xsl:choose>
          </xsl:when>
208 
          <xsl:when test="element-available('saxon:output')">
210         <xsl:choose>
              <!-- Handle the permutations ... -->
212           <xsl:when test="$media-type != ''">
                <xsl:choose>
214               <xsl:when
                    test="$doctype-public != '' and $doctype-system != ''">
216                 <saxon:output
                      saxon:character-representation="{$saxon.character.representation}"
218                   href="{$filename}" method="{$method}"
                      encoding="{$encoding}" indent="{$indent}"
220                   omit-xml-declaration="{$omit-xml-declaration}"
                      cdata-section-elements="{$cdata-section-elements}"
222                   media-type="{$media-type}"
                      doctype-public="{$doctype-public}"
224                   doctype-system="{$doctype-system}"
                      standalone="{$standalone}">
226                   <xsl:copy-of select="$content"/>
                    </saxon:output>
228               </xsl:when>
                  <xsl:when
230                 test="$doctype-public != '' and $doctype-system = ''">
                    <saxon:output
232                   saxon:character-representation="{$saxon.character.representation}"
                      href="{$filename}" method="{$method}"
234                   encoding="{$encoding}" indent="{$indent}"
                      omit-xml-declaration="{$omit-xml-declaration}"
236                   cdata-section-elements="{$cdata-section-elements}"
                      media-type="{$media-type}"
238                   doctype-public="{$doctype-public}"
                      standalone="{$standalone}">
240                   <xsl:copy-of select="$content"/>
                    </saxon:output>
242               </xsl:when>
                  <xsl:when
244                 test="$doctype-public = '' and $doctype-system != ''">
                    <saxon:output
246                   saxon:character-representation="{$saxon.character.representation}"
                      href="{$filename}" method="{$method}"
248                   encoding="{$encoding}" indent="{$indent}"
                      omit-xml-declaration="{$omit-xml-declaration}"
250                   cdata-section-elements="{$cdata-section-elements}"
                      media-type="{$media-type}"
252                   doctype-system="{$doctype-system}"
                      standalone="{$standalone}">
254                   <xsl:copy-of select="$content"/>
                    </saxon:output>
256               </xsl:when>
                  <xsl:otherwise>
258                 <!-- $doctype-public = '' and $doctype-system = ''"> -->
                    <saxon:output
260                   saxon:character-representation="{$saxon.character.representation}"
                      href="{$filename}" method="{$method}"
262                   encoding="{$encoding}" indent="{$indent}"
                      omit-xml-declaration="{$omit-xml-declaration}"
264                   cdata-section-elements="{$cdata-section-elements}"
                      media-type="{$media-type}" standalone="{$standalone}">
266                   <xsl:copy-of select="$content"/>
                    </saxon:output>
268               </xsl:otherwise>
                </xsl:choose>
270           </xsl:when>
              <xsl:otherwise>
272             <xsl:choose>
                  <xsl:when
274                 test="$doctype-public != '' and $doctype-system != ''">
                    <saxon:output
276                   saxon:character-representation="{$saxon.character.representation}"
                      href="{$filename}" method="{$method}"
278                   encoding="{$encoding}" indent="{$indent}"
                      omit-xml-declaration="{$omit-xml-declaration}"
280                   cdata-section-elements="{$cdata-section-elements}"
                      doctype-public="{$doctype-public}"
282                   doctype-system="{$doctype-system}"
                      standalone="{$standalone}">
284                   <xsl:copy-of select="$content"/>
                    </saxon:output>
286               </xsl:when>
                  <xsl:when
288                 test="$doctype-public != '' and $doctype-system = ''">
                    <saxon:output
290                   saxon:character-representation="{$saxon.character.representation}"
                      href="{$filename}" method="{$method}"
292                   encoding="{$encoding}" indent="{$indent}"
                      omit-xml-declaration="{$omit-xml-declaration}"
294                   cdata-section-elements="{$cdata-section-elements}"
                      doctype-public="{$doctype-public}"
296                   standalone="{$standalone}">
                      <xsl:copy-of select="$content"/>
298                 </saxon:output>
                  </xsl:when>
300               <xsl:when
                    test="$doctype-public = '' and $doctype-system != ''">
302                 <saxon:output
                      saxon:character-representation="{$saxon.character.representation}"
304                   href="{$filename}" method="{$method}"
                      encoding="{$encoding}" indent="{$indent}"
306                   omit-xml-declaration="{$omit-xml-declaration}"
                      cdata-section-elements="{$cdata-section-elements}"
308                   doctype-system="{$doctype-system}"
                      standalone="{$standalone}">
310                   <xsl:copy-of select="$content"/>
                    </saxon:output>
312               </xsl:when>
                  <xsl:otherwise>
314                 <!-- $doctype-public = '' and $doctype-system = ''"> -->
                    <saxon:output
316                   saxon:character-representation="{$saxon.character.representation}"
                      href="{$filename}" method="{$method}"
318                   encoding="{$encoding}" indent="{$indent}"
                      omit-xml-declaration="{$omit-xml-declaration}"
320                   cdata-section-elements="{$cdata-section-elements}"
                      standalone="{$standalone}">
322                   <xsl:copy-of select="$content"/>
                    </saxon:output>
324               </xsl:otherwise>
                </xsl:choose>
326           </xsl:otherwise>
            </xsl:choose>
328       </xsl:when>
    
330       <xsl:when test="element-available('redirect:write')">
            <!-- Xalan uses redirect -->
332         <redirect:write file="{$filename}">
              <xsl:copy-of select="$content"/>
334         </redirect:write>
          </xsl:when>
336 
          <xsl:otherwise>
338         <!-- it doesn't matter since we won't be making chunks... -->
            <xsl:message terminate="yes">
340           <xsl:text>Can't make chunks with </xsl:text>
              <xsl:value-of select="system-property('xsl:vendor')"/>
342           <xsl:text>'s processor.</xsl:text>
            </xsl:message>
344       </xsl:otherwise>
        </xsl:choose>
346   </xsl:template>
    
348   <xsl:template name="write.xml.chunk">
        <xsl:param name="filename" select="''"/>
350     <xsl:param name="quiet" select="$chunker.output.quiet"/>
        <xsl:param name="suppress-context-node-name" select="0"/>
352     <xsl:param name="message-prolog"/>
        <xsl:param name="message-epilog"/>
354     <xsl:param name="method" select="'xml'"/>
        <xsl:param name="encoding" select="$chunker.output.encoding"/>
356     <xsl:param name="media-type" select="$chunker.output.media-type"/>
        <xsl:param name="content"/>
358     <xsl:call-template name="write.chunk">
          <xsl:with-param name="filename" select="$filename"/>
360       <xsl:with-param name="quiet" select="$quiet"/>
          <xsl:with-param name="suppress-context-node-name"
362         select="$suppress-context-node-name"/>
          <xsl:with-param name="message-prolog" select="$message-prolog"/>
364       <xsl:with-param name="message-epilog" select="$message-epilog"/>
          <xsl:with-param name="method" select="$method"/>
366       <xsl:with-param name="encoding" select="$encoding"/>
          <xsl:with-param name="indent" select="'yes'"/>
368       <xsl:with-param name="omit-xml-declaration" select="'no'"/>
          <xsl:with-param name="standalone" select="'no'"/>
370       <xsl:with-param name="doctype-public"/>
          <xsl:with-param name="doctype-system"/>
372       <xsl:with-param name="media-type" select="$media-type"/>
          <xsl:with-param name="cdata-section-elements"/>
374       <xsl:with-param name="content" select="$content"/>
        </xsl:call-template>
376   </xsl:template>
    </xsl:stylesheet>

It can be customized with several parameters:

base.dir

Determines the output directory

dbsplit.chunk.depth

Controls the depth where to split

dbsplit.ext

Defines the file extension for each filename written.

dbsplit.root.filename

Identifies the name of the root filename when splitted

use.id.as.filename

Uses ID values as filenames

rootid

Specify the root element to split

Splitting with the dbautosplit

TBD

Discussion

TDB

Difficulty: ★☆☆ (easy)
Keywords: extracting one element, rootid, xref, cross-references

Problem

You have a big DocBook document and you need to extract one structural element like a chapter, appendix etc. to edit or process it separately from the main document.

Solution

To make the solution work, the structural element needs an ID attribute. If this is available, use the following stylesheet:

Example 3.8. Extracting Stylesheet rootid.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  4 
      <xsl:key name="id" match="*" use="@id|@xml:id"/>
  6   <!-- Contains the ID attribute of the extracted element: -->
      <xsl:param name="rootid"/>
  8   <!-- Controls some log messages: 0=off, 1=on -->
      <xsl:param name="rootid.debug" select="0"/>
 10 
      <xsl:template match="/">
 12     <xsl:choose>
          <xsl:when test="$rootid !=''">
 14         <xsl:if test="count(key('id',$rootid)) = 0">
              <xsl:message terminate="yes">
 16             <xsl:text>ID '</xsl:text>
                <xsl:value-of select="$rootid"/>
 18             <xsl:text>' not found in document.</xsl:text>
              </xsl:message>
 20         </xsl:if>
            <xsl:call-template name="rootid.debug.message"/>
 22         <xsl:call-template name="rootid.process"/>
          </xsl:when>
 24       <xsl:otherwise>
            <xsl:call-template name="normal.process"/>
 26       </xsl:otherwise>
        </xsl:choose>
 28   </xsl:template>
    
 30   <xsl:template name="rootid.debug.message">
        <xsl:if test="$rootid.debug != 0">
 32       <xsl:message>
            <xsl:text>Using ID </xsl:text>
 34         <xsl:value-of select="concat('&quot;', $rootid, '&quot;')"/>
          </xsl:message>
 36     </xsl:if>
      </xsl:template>
 38   
      <xsl:template name="rootid.process">
 40     <xsl:apply-templates select="key('id',$rootid)" mode="process.root"/>
      </xsl:template>
 42 
      <xsl:template name="normal.process">
 44     <xsl:apply-templates/>
      </xsl:template>
 46   
      <xsl:template match="node() | @*" mode="process.root">
 48     <xsl:copy>
          <xsl:apply-templates select="@* | node()" mode="process.root"/>
 50     </xsl:copy>
      </xsl:template>
 52 </xsl:stylesheet>

Pass the rootid parameter to your XSLT processor with the corresponding ID, for example:

xsltproc --stringparam rootid intro rootid.xsl XML_FILE

The result contains only the element with the corresponding ID value and everything inside it.

Discussion

This solution cuts off the element with the corresponding ID and copies the element itself and its children to the output stream. The copying is done in the process.root mode. The stylesheet does not apply any further processing. This can be a disadvantage, for example, a xref pointing outside of the respective element. If the resulting file contains such a cross reference, it will not be valid anymore.

It is possible to convert such cross references into a “resolved form” by using the following code:

Example 3.9. rootid-resolve-xrefs.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  4   xmlns:xlink="http://www.w3.org/1999/xlink"
      xmlns:d="http://docbook.org/ns/docbook">
  6   
      <xsl:import href="rootid.xsl"/>
  8   
      <xsl:template match="d:xref" mode="process.root">
 10     <xsl:variable name="xhref" select="@xlink:href"/>
        <!-- is the @xlink:href a local idref link? -->
 12     <xsl:variable name="xlink.idref">
          <xsl:choose>
 14         <xsl:when test="starts-with($xhref,'#')">
              <xsl:value-of select="substring($xhref, 2)"/>
 16         </xsl:when>
            <xsl:when test="contains($xhref, '://')">
 18          <xsl:message>
                <xsl:text>ERROR: Don't know what do do with @xlink:href: </xsl:text>
 20             <xsl:value-of select="$xhref"/></xsl:message> 
            </xsl:when>
 22         <xsl:otherwise/>
          </xsl:choose>
 24     </xsl:variable>
        <xsl:variable name="xlink.targets" select="key('id',$xlink.idref)"/>
 26     <xsl:variable name="linkend.targets" select="key('id',@linkend)"/>
        <xsl:variable name="target" select="($xlink.targets | $linkend.targets)[1]"/>
 28     <xsl:variable name="refelem" select="local-name($target)"/>
        
 30     <xsl:variable name="this.div" 
          select="ancestor-or-self::d:*[@xml:id = $rootid][1]"/>
 32     <xsl:variable name="target.div"
          select="$target/ancestor-or-self::d:*[@xml:id = $rootid][1]"/>
 34 
        <xsl:choose>
 36       <xsl:when test="generate-id($this.div) = generate-id($target.div)">
            <xsl:copy-of select="."/>
 38       </xsl:when>
          <xsl:otherwise>
 40         <phrase xmlns="http://docbook.org/ns/docbook" remap="xref">
              <xsl:choose>
 42             <xsl:when test="@linkend">
                  <xsl:attribute name="role">
 44                 <xsl:value-of select="@linkend"/>
                  </xsl:attribute>
 46             </xsl:when>
                <xsl:when test="$xlink.idref != ''">
 48               <xsl:attribute name="role">
                    <xsl:value-of select="$xlink.idref"/>
 50               </xsl:attribute>
                </xsl:when>
 52             <xsl:otherwise>
                  <xsl:attribute name="role">
 54                 <xsl:value-of select="$xhref"/>
                  </xsl:attribute>
 56             </xsl:otherwise>
              </xsl:choose>
 58           <xsl:apply-templates
                select="@*[local-name() != 'linkend' and
 60                        local-name() != 'href']"
                mode="process.root"/>
 62           <xsl:apply-templates
                select="($target/ancestor-or-self::d:*[d:title])[last()]/d:title/node()"
 64             mode="process.root"/>
            </phrase>
 66       </xsl:otherwise>
        </xsl:choose>
 68   </xsl:template>
    </xsl:stylesheet>

The stylesheet in Example 3.9, “rootid-resolve-xrefs.xsl imports the rootid.xsl and inherits all templates. To implement a different behaviour we need to add a new template matching for the xref element in mode process.root.

The template contains mostly code from the DocBook XSL stylesheets with some minor changes. The general behaviour is described in the following sequence:

  1. Make sure, everything is in place and a xlink:href attribute does not contain a :// string. If this is the case emit an error message.

  2. Populate the variables xlink.targets and linkend.targets with the target node. For xlink.targets use the XLink attribute xlink:href, for the variable linkend.targets use the linkend attribute. As only one of these attributes can be available, but not both, the variables are filled with zero nodes or more.

  3. Create the set union of the variables xlink.targets and linkend.targets and select only one node.

  4. Now it gets interesting: our context node is in xref. We need to know the node where the value of the xml:id attribute equals our rootid parameter. We climb up tree with the ancestor-or-self axis specifier and select every DocBook element. With the predicate [@xml:id = $rootid] the node set is filtered and only those element(s) are preserved where this expression is true. Only one node from the node set is selected.

    This is done also for the target node and the result is saved in the variable target.div

  5. The two node from the previous operation are compared through the generate-id function. That leaves two options:

    • Both nodes are equal  The xref points somewhere inside the tree under the rootid element. That means, we can copy the xref element.

    • Both nodes are not equal  The xref points outside of the rootid element. That means, you need to “resolve” the xref element to prevent validation errors.

  6. If the xref needs to be revamped, we use the phrase element, copy all attributes (except linkend and xlink:href), and copy anything inside the title of the target node. As the target node could not be a title itself, we use again the ancestor-or-self axis to climb up the tree and select the first emerging title.

TODO: Add graphic to illustrate the method

See Also

Section 3.5, “Splitting DocBook Documents” uses a different approach without needing an ID attribute.

Difficulty: ★☆☆ (easy)
Keywords: sectX, section, sectX to section

Problem

You need to transform every sectX element into a section element.

Solution

This problem is solved through the following XSLT stylesheet:

Example 3.10. Transforms every sectX Element into a section Element
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:d="http://docbook.org/ns/docbook"
  4   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
  6   <xsl:import href="copy.xsl"/>
      
  8   <xsl:template match="d:sect1|d:sect2|d:sect3|d:sect4|d:sect5">
        <xsl:element name="section" namespace="http://docbook.org/ns/docbook">
 10       <xsl:apply-templates select="node()"/>
        </xsl:element>
 12   </xsl:template>
    </xsl:stylesheet>

Discussion

The stylesheet from Example 3.10, “Transforms every sectX Element into a section Element” is very easy: it imports the standard rules to copy every node from copy.xsl and create special rules for all sectX elements. As every sectX element creates the same structure, we can collect it in one template rule.

Difficulty: ★☆☆ (easy)
Keywords: sectX, section, section to sectX

Problem

You need to transform every sectX element into a section element.

Solution

This problem is solved through the following XSLT stylesheet:

Example 3.11. Transforms every sectX Element into a section Element
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet
      xmlns:d="http://docbook.org/ns/docbook"
  4   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
  6   
      <xsl:import href="copy.xsl"/>
  8   
      <xsl:template match="d:section">
 10     <xsl:variable name="level" select="count(ancestor::*)"/>
        <xsl:element name="sect{$level}" namespace="http://docbook.org/ns/docbook">
 12       <xsl:copy-of select="@*"/>
          <xsl:apply-templates/>
 14     </xsl:element>
      </xsl:template>
 16   
    </xsl:stylesheet>

Discussion

The above stylesheet calculates the section level with the ancestor axis, because the amount of elements is directly correlated with the level of the corresponding section. With an attribute value template it is inserted in the name attribute.

There is one caveat: The stylesheet does not check if the limit is reached. Currently (with version 5.1), DocBook supports levels up to 5. If you nest your section elements too deep, you can end up with, let's say, sect8 which is not allowed in DocBook. To avoid making mistakes, it is better to check the level:

Example 3.12. Error Checking of Section Levels
  1 <xsl:template match="d:section">
  2   <xsl:variable name="level" select="count(ancestor::*)"/>
      <xsl:choose>
  4     <xsl:when test="$level &lt;= 5">
          <xsl:element name="sect{$level}"
  6           namespace="http://docbook.org/ns/docbook">
            <xsl:copy-of select="@*"/>
  8         <xsl:apply-templates/>
          </xsl:element>
 10     </xsl:when>
        <xsl:otherwise>
 12       <xsl:message>ERROR: section <xsl:value-of
              select="normalize-space(d:title)"/> to deep</xsl:message>
 14       <!-- What to do if the section is too deeply nested? -->
        </xsl:otherwise>
 16   </xsl:choose>    
    </xsl:template>

Amend the stylesheet when the section is too deeply nested (see above comment). You could avoid the section level (which is a bad idea) but it's better to rework the source document.

If you want, you can stop the transformation if the section level is too high. Change the xsl:message as follows:

<xsl:message terminate="yes">...
Difficulty: ★★★ (hard)
Keywords: bridgehead, section

Problem

You have a DocBook document which contains several bridgehead elements. The bridgehead has to be transformed into the correct section structure.

Solution

A bridgehead element is a “free-floating heading”. In most cases it is a bad idea as it is difficult to handle in XSLT. To create the correct section hierarchy, a stylesheet need to collect all nodes between a bridgehead element and the next one. The following stylesheet uses a set difference method:

Example 3.13. Transforms every bridgehead Element into a section Element
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"  
      xmlns:d="http://docbook.org/ns/docbook"
  4   xmlns="http://docbook.org/ns/docbook"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  6   
      <xsl:import href="copy.xsl"/>
  8   
      <xsl:output indent="yes"/>
 10   <xsl:strip-space elements="*"/>
      <xsl:preserve-space elements="d:screen d:programlisting d:literallayout"/>
 12   
      <xsl:template match="d:section[d:bridgehead]">
 14     <!-- All nodes inside our section: -->
        <xsl:variable name="node1" select="node()"/>
 16     <!-- All nodes -->
        <xsl:variable name="node2" 
 18       select="d:bridgehead[1]|
                  d:bridgehead[1]/following-sibling::node()"/>
 20     
        <!-- Copy our section with all attributes, apply the set difference
 22       and investigate the first bridgehead 
        -->
 24     <xsl:copy>
          <xsl:copy-of select="@*"/>
 26       <xsl:apply-templates select="$node1[count(.|$node2) != count($node2)]"/>
          <xsl:apply-templates select="d:bridgehead[1]"/>
 28     </xsl:copy>
        <xsl:text>&#10;</xsl:text>
 30   </xsl:template>
      
 32   <xsl:template match="d:bridgehead">
        <!-- All nodes who follow bridgeheads: -->
 34     <xsl:variable name="node1" 
          select="following-sibling::node()"/>
 36     <!-- All nodes who follow the next bridgehead including the next
             bridgehead.
 38          The next bridgehead element is included as we don't want it
             in the set difference:
 40     -->
        <xsl:variable name="node2"
 42       select="following-sibling::d:bridgehead[1]|
                  following-sibling::d:bridgehead[1]/following-sibling::node()"/>   
 44 
        <!-- Create the section element with all attributes and apply
 46       standard rules for the diff set -->
        <xsl:element name="section">
 48       <xsl:copy-of select="@*"/>
          <xsl:text>&#10;  </xsl:text>
 50       <xsl:element name="title">
            <xsl:apply-templates select="node()"/>
 52       </xsl:element>
          <xsl:apply-templates select="$node1[count(.|$node2) != count($node2)]"/>
 54     </xsl:element>
        
 56     <!-- Process the next bridgehead -->
        <xsl:apply-templates select="following-sibling::d:bridgehead[1]"/>
 58   </xsl:template>
      
 60 </xsl:stylesheet>

Discussion

The solution is unfortunately not very trivial in XSLT 1.0. The template rule d:section[d:bridgehead] matches only sections which contain one or more bridgehead elements. The template rule performs the following steps:

  1. Collect all nodes inside a section and save it in variable node1.

  2. Collect all nodes who follows the next bridgehead including the next bridgehead itself and save it in variable node2.

  3. Creates a section element and copy all attributes from the bridgehead element.

  4. Creates a title element and apply the content from the bridgehead element. This copies the content from bridgehead.

  5. Calculates the set difference between node1 and node2. This weird expression is needed in XSLT 1.0 to create a node set which contains only those nodes up to the first bridgehead.

  6. Handle the first bridgehead element which is covered by our bridgehead template rule.

The bridgehead template rule is responsible for transforming the current bridgehead element into a section. It is also responsible for the next bridgeheads. The rule performs the following steps:

  1. Collect all nodes following of the current bridgehead element and save it in variable node1.

  2. Collect all nodes following of the next bridgehead element including the next bridgehead element itself. Save the node set in variable node2.

  3. Creates a section element and copy all attributes from the bridgehead element.

  4. Creates a title element and apply the content from the bridgehead element. This copies the content from bridgehead.

  5. Calculate the set difference between node1 and node2 and apply the correct template rule (usually they are just copied).

  6. Close the section element and handle the next bridgehead element.

Difficulty: ★★★ (hard)
Keywords: block elements, inline elements

Jeni Tennison

Dave Pawson

Problem

DocBook allows to insert block elements like example, figure, etc. to be inserted in paras. This is sometimes hard to process with XSLT and you want to move those block elements outside of your paragraph. After this modification, the paragraph contains only text and inline elements (like simpara).

Solution

The solution explained

Example 3.14. move-blocks-outof-para.xsl
  1 <!DOCTYPE xsl:stylesheet
  2 [
     <!ENTITY dbblocks "d:address|d:bibliolist|d:blockquote|d:bridgehead|d:calloutlist|d:caution|d:classsynopsis|d:cmdsynopsis|d:constraintdef|d:constructorsynopsis|d:destructorsynopsis|d:epigraph|d:equation|d:example|d:fieldsynopsis|d:figure|d:funcsynopsis|d:glosslist|d:important|d:informalexample|d:informalfigure|d:informaltable|d:itemizedlist|d:literallayout|d:mediaobject|d:methodsynopsis|d:msgset|d:note|d:orderedlist|d:procedure|d:procedure|d:productionset|d:programlisting|d:programlistingco|d:qandaset|d:revhistory|d:screen|d:screenco|d:screenshot|d:segmentedlist|d:sidebar|d:simplelist|d:synopsis|d:table|d:task|d:tip|d:variablelist|d:warning">
  4  <!ENTITY dbselfblocks "self::d:address|self::d:bibliolist|self::d:blockquote|self::d:bridgehead|self::d:calloutlist|self::d:caution|self::d:classsynopsis|self::d:cmdsynopsis|self::d:constraintdef|self::d:constructorsynopsis|self::d:destructorsynopsis|self::d:epigraph|self::d:equation|self::d:example|self::d:fieldsynopsis|self::d:figure|self::d:funcsynopsis|self::d:glosslist|self::d:important|self::d:informalexample|self::d:informalfigure|self::d:informaltable|self::d:itemizedlist|self::d:literallayout|self::d:mediaobject|self::d:methodsynopsis|self::d:msgset|self::d:note|self::d:orderedlist|self::d:procedure|self::d:procedure|self::d:productionset|self::d:programlisting|self::d:programlistingco|self::d:qandaset|self::d:revhistory|self::d:screen|self::d:screenco|self::d:screenshot|self::d:segmentedlist|self::d:sidebar|self::d:simplelist|self::d:synopsis|self::d:table|self::d:task|self::d:tip|self::d:variablelist|self::d:warning">
     <!ENTITY dbblocksinpara "d:para/d:address|d:para/d:bibliolist|d:para/d:blockquote|d:para/d:bridgehead|d:para/d:calloutlist|d:para/d:caution|d:para/d:classsynopsis|d:para/d:cmdsynopsis|d:para/d:constraintdef|d:para/d:constructorsynopsis|d:para/d:destructorsynopsis|d:para/d:epigraph|d:para/d:equation|d:para/d:example|d:para/d:fieldsynopsis|d:para/d:figure|d:para/d:funcsynopsis|d:para/d:glosslist|d:para/d:important|d:para/d:informalexample|d:para/d:informalfigure|d:para/d:informaltable|d:para/d:itemizedlist|d:para/d:literallayout|d:para/d:mediaobject|d:para/d:methodsynopsis|d:para/d:msgset|d:para/d:note|d:para/d:orderedlist|d:para/d:procedure|d:para/d:procedure|d:para/d:productionset|d:para/d:programlisting|d:para/d:programlistingco|d:para/d:qandaset|d:para/d:revhistory|d:para/d:screen|d:para/d:screenco|d:para/d:screenshot|d:para/d:segmentedlist|d:para/d:sidebar|d:para/d:simplelist|d:para/d:synopsis|d:para/d:table|d:para/d:task|d:para/d:tip|d:para/d:variablelist|d:para/d:warning">
  6 ]>
    <xsl:stylesheet xmlns:d="http://docbook.org/ns/docbook"
  8   xmlns="http://docbook.org/ns/docbook"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 10 
      <xsl:import href="copy.xsl"/>
 12 
      <xsl:strip-space elements="d:para"/>
 14   <xsl:preserve-space elements="d:screen d:programlisting d:literallayout"/>
      <xsl:output indent="yes"/>
 16 
      <xsl:template match="d:para">
 18     <xsl:apply-templates select="node()[1]"/>
      </xsl:template>
 20 
      <xsl:template match="&dbblocksinpara;">
 22     <xsl:copy-of select="."/>
        <xsl:text>&#10;</xsl:text>
 24     <xsl:apply-templates select="following-sibling::node()[1]"/>
      </xsl:template>
 26 
      <xsl:template match="d:para/*|d:para/text()">
 28     <xsl:element name="{local-name(..)}">
          <xsl:apply-templates select="." mode="copy"/>
 30     </xsl:element>
        <xsl:text>&#10;</xsl:text>
 32     <xsl:apply-templates
          select="following-sibling::*[&dbselfblocks;][1]"/>
 34   </xsl:template>
    
 36   <xsl:template match="d:para/*|d:para/text()" mode="copy">
        <xsl:copy-of select="."/>
 38     <xsl:if test="not(following-sibling::node()[1][&dbselfblocks;])">
          <xsl:apply-templates select="following-sibling::node()[1]"
 40         mode="copy"/>
        </xsl:if>
 42   </xsl:template>
    
 44 </xsl:stylesheet>

Discussion

TBD

Difficulty: ★★☆ (medium)
Keywords: index, automatically insert indices, consistency

Problem

You want to add index entries (also known as indexterms) automatically into your document.

Solution

To see how the automatic addition works, the following procedure demonstrate this for the element envar.

Adding indexterm Elements to envar
  1. Use the element envar in your document as usual. By default all envar elements get an indexterm. In cases you do not want this, add the attribute condition with its value noindex to suppress indexterm generation. This is done in the second para element:

    Example 3.15. profile-envar.xml
      1 <article  version="5.0"
      2   xmlns="http://docbook.org/ns/docbook">
          <title>Profiling Test</title>
      4   <para>Environment variable <envar>XML_CATALOG_FILES</envar></para>
          <para>Environment variable <envar condition="noindex">FOO</envar></para>
      6   <para>Environment variable <envar os="windows">Path</envar><envar 
            os="linux">PATH</envar></para>
      8 </article>
  2. Create a stylesheet profile-tags.xsl with the following content:

    Example 3.16. profile-tag.xsl
      1 <xsl:stylesheet version="1.0"
      2   xmlns:d="http://docbook.org/ns/docbook"
          xmlns="http://docbook.org/ns/docbook"
      4   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          
      6 <xsl:param name="preferred">pref</xsl:param>
        
      8 <xsl:template name="check.index">
          <xsl:param name="node" select="."/>
     10   <xsl:param name="default" select="1"/>
            
     12     <xsl:choose>
              <xsl:when test="$node/@condition = 'noindex'">0</xsl:when>
     14       <xsl:when test="$node/@condition = 'index'">1</xsl:when>    
              <xsl:otherwise><xsl:value-of select="$default"/></xsl:otherwise>
     16     </xsl:choose>  
        </xsl:template>
     18 
        <xsl:template match="d:footnote|d:title|d:indexterm" mode="profile">
     20   <!-- Indexterms doesn't/shouldn't occur in the descendants of
               these elements so just copy it -->
     22   <xsl:copy-of select="."/>
        </xsl:template>
     24 
        <xsl:template match="d:envar" mode="profile">
     26     <xsl:variable name="do.index">
              <xsl:call-template name="check.index"/>
     28     </xsl:variable>
        
     30     <!-- Copy original element -->
            <xsl:copy-of select="."/>
     32   
            <xsl:if test="$do.index != 0">
     34       <indexterm>
                <primary><xsl:value-of select="."/></primary>
     36       </indexterm>
              <indexterm>
     38         <xsl:if test="contains(@conformance, $preferred)">
                   <xsl:attribute name="significance">preferred</xsl:attribute>
     40         </xsl:if>
                <primary>environment variables</primary>
     42         <secondary><xsl:value-of select="."/></secondary>
              </indexterm>
     44     </xsl:if>
        </xsl:template>
     46 </xsl:stylesheet>
  3. Create the stylesheet add-indexterms.xsl. This stylesheet is based on profile.xsl of the DocBook XSL stylesheets. It contains the special mode profile to process elements to observe profiling conditions.

    Example 3.17. add-indexterms.xsl
      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <!DOCTYPE xsl:stylesheet
        [
      4   <!ENTITY db "http://docbook.sourceforge.net/release/xsl-ns/current"> 
        ]>
      6 <xsl:stylesheet version="1.0"
          xmlns:d="http://docbook.org/ns/docbook"
      8   xmlns="http://docbook.org/ns/docbook"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
     10 
        <xsl:import href="&db;/profiling/profile.xsl"/>
     12 <xsl:output indent="yes" method="xml"/>
        <xsl:include href="profile-tags.xsl"/>
     14 
        </xsl:stylesheet>
  4. Transform your document:

    xsltproc add-indexterms.xsl profile-envar.xml

After applying the stylesheet add-indexterms.xsl you will get the following output:

Example 3.18. Output of the Transformation
  1 <article xmlns="http://docbook.org/ns/docbook" version="5.0">
  2   <title>Profiling Test</title>
      <para>Environment variable <envar>XML_CATALOG_FILES</envar><indexterm>
  4     <primary>XML_CATALOG_FILES</primary>
      </indexterm><indexterm>
  6     <primary>environment variables</primary>
        <secondary>XML_CATALOG_FILES</secondary>
  8     </indexterm></para>
      <para>Environment variable <envar condition="noindex">FOO</envar></para>
 10   <para>Environment variable <envar os="windows"
            >Path</envar><indexterm><primary>Path</primary></indexterm><indexterm><primary>environment
 12         variables</primary><secondary>Path</secondary></indexterm><envar
          os="linux"
 14       >PATH</envar><indexterm>
            <primary>PATH</primary>
 16       </indexterm><indexterm>
            <primary>environment variables</primary>
 18         <secondary>PATH</secondary>
          </indexterm></para>
 20 </article>

Discussion

Let´s go back at the beginning first. Assume you want to show an environment variable in the index. Usually you would mark up the text with the envar element and add an indexterm right after the first one. As is is useful to find the index term also under the primary term “environment variables”, you add an additional indexterm. This could look like this:

  1 <para>Use the <envar>PATH</envar><indexterm>
  2         <primary>PATH</primary>
          </indexterm><indexterm>
  4         <primary>environment variables</primary>
            <secondary>PATH</secondary>
  6       </indexterm>
          to do ...
  8 </para>

Although this is the usual method, it has some drawbacks:

  • It is hard to read  If you are get used to read the bare XML code, it is hard to read as the text is broken into pieces. The text is cluttered with indexterm elements all along.

  • It may be inconsistent  If you forgot the “s” in the primary index term it will lead to double entries (one singular and one plural form). This lead to inconsistencies. It can be painful if you have to go through the complete document just to fix the singular form into the plural form (or vice versa).

  • Whitespace could matter  The indexterm element(s) start directly after your term. If you or your editor introduces one or more whitespaces after your dedicated index term, in the worst case it could lead to a wrong page number in the index. This mainly affects the PDF rather than any online formats but could confuse your readers.

All of the above problems can be solved with the stylesheet from Example 3.16, “profile-tag.xsl. It exploits the DocBook XSL stylesheet´s profiling mechanism. Normally, profiling is a method to remove certain structures from a document rather than add something. In our case we use the special profile mode to customize the automatic index term addition.

With the above stylesheet, it is possible to influence how your index terms appear. This is done with the condition[7] attribute, demonstrated on our envar example:

<envar></envar>

Adds the indexterms directly after the envar element.

<envar condition="index"></envar>

Same as the previous entry.

<envar condition="noindex"></envar>

Suppresses any automatic generation of index entries.

<envar condition="pref"></envar>

Adds an preferred index entry. The keyword “pref” can be customized through the preferred parameter. If the keyword is added in the condition attribute, the following code is created:

<indexterm significance="preferred">...</indexterm>

This method can not solve all index problems. You should know some of its limits:

  • Document Type  Technical documents are more applicable than novels as the former contains usually a set of elements which are consistently used.

  • Consistent Elements  The document needs not only consistently use the same elements for the same structure, it has to use a specific element in the first place. For example, if you want to show your configuration files in your index, you need to mark it up with filename, otherwise this method has no chance.

  • Needed Elements  Similar to the previous point, you have to know which elements you need to show up in the index. You have to select from all possible inline elements only a handful which you consider important enough.

  • Only for Inline Elements  This method works only for inline elements well. DocBook´s inline elements occur usually inside a paragraph but can also show up in a title.

  • Hard-coded Primary Entry  It can be critized to add hard-coded text into the stylesheet profile-tag.xsl (here: “environment variables”). If you maintain different languages, you should replace it with a more general solution and move the language specific text into language files as described in Section 2.8, “Extending Language Files with Your Own Text”.

Although this method does not replace hand-written index entries, it can ease the pain. Especially for those entries which can be be inserted automatically it improves consistency. The method described above can also implemented for other inline elements, like persons, functions, etc.

Difficulty: ★★☆ (medium)
Keywords: version control system, revhistory, Bazaar, Git, Mercurial, Subversion

Problem

You want to include revision information into your DocBook document from your version control systems, like Bazaar, Subversion, Mercurial, Git, and others.

Solution

Usually, the solution for each version control system is to output its log into its specific XML output and transform it with XSLT into a revhistory element.

Bazaar

Bazaar does not come with a predefined XML output. If you need this functionality, you have to install the xmloutput plugin first. This brings the --xml option to the log subcommand. Proceed as follows:

Installing the Bazaar Plugin xmloutput
  1. Download the tar archive from http://wiki.bazaar.canonical.com/XMLOutput.

  2. Unpack the archive.

  3. Change to the extension directory (usually something like bzr-xmloutput-VERSION) and run:

    python setup build_ext
  4. Copy the result directory build/lib/bzrlib/plugins/xmloutput/ to your plugin directory. For Linux it is something like $HOME/.bazaar/plugins/, for Windows copy it to $APPDATA/bazaar/VERSION/plugins

  5. Check if the plugin is correctly detected:

    bzr plugins

    You should see the following line:

      1 xmloutput VERSION
      2     This plugin adds an option (--xml) to log and provides an xml version of 
            some built-in commands.

After you have successully installed the plugin, create the log output in XML with the following command:

bzr log --xml REPO > bzr-log.xml

To convert the previous log file into DocBook's revhistory, use the following stylesheet:

Example 3.19. Stylesheet to Convert Bazaar's Log File
TBD
Git

Git does not have any options to turn the log into XML. However, with the --pretty option you can collect the information and wrap it into any XML elements you wish. The following command uses this option and sed to insert the <logs> start tag in the first line and </logs> end tag in the last line:

git log --date=iso --pretty=format:"<logentry revision='%h'>%n <author email='%ae'>%an</author>%n <date>%ad</date>%n <msg xml:space='preserve'>%s</msg>%n</logentry>" \
  | sed -e '1i<logs>' -e '$a</logs>' > git-log.xml

As the element names can be freely chosen, we use the same names as in Example 3.20, “Mercurial Log File in XML”. This allows us to use the stylesheet from Example 3.21, “Stylesheet hg2revhistory.xsl to Convert Mercurial XML Log Files into DocBook's revhistory.

Mercurial

Mercurial has the --style option to output its log into XML:

hg log --style xml > hg-log.xml

The XML file of the Mercurial log looks like this:

Example 3.20. Mercurial Log File in XML
  1 <log>
  2   <logentry revision="69"
        node="dfadd024594c4083362fe6919264362803dcd285">
  4     <tag>tip</tag>
        <author email="tux@example.de">Tux Penguin</author>
  6     <date>2011-05-22T01:56:21+02:00</date>
        <msg xml:space="preserve">Corrected xml:id attribute</msg>
  8     <paths>
          <path action="M">xml/structure/topic.extract-element.xml</path>
 10     </paths>
      </logentry>
 12   <logentry revision="68"
        node="833287df8943d0bab5ec65ec8aafe5bc42002289">
 14     <author email="wilber@example.de">Wilber Gimp</author>
        <date>2011-05-22T01:56:03+02:00</date>
 16     <msg xml:space="preserve">Changed chapter title</msg>
        <paths>
 18       <path action="M">xml/structure/topic.revision-list.xml</path>
        </paths>
 20   </logentry>
      <!-- Many more entries ... -->
 22 </log

The following stylesheet converts the log file from Example 3.20, “Mercurial Log File in XML” into DocBook's revhistory:

Example 3.21. Stylesheet hg2revhistory.xsl to Convert Mercurial XML Log Files into DocBook's revhistory
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <!DOCTYPE xsl:stylesheet
    [
  4   <!ENTITY dbns "http://docbook.org/ns/docbook">
    ]>
  6 <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  8   
      <xsl:output method="xml" indent="yes"/>
 10   
      <xsl:param name="include.paths" select="1"/>
 12   <xsl:param name="include.copies" select="1"/>
      
 14   <xsl:template match="log">
        <revhistory xmlns="&dbns;">
 16       <xsl:apply-templates/>
        </revhistory>
 18   </xsl:template>
      
 20   <xsl:template match="logentry">
        <revhistory xmlns="&dbns;">
 22       <xsl:apply-templates select="@revision|*"/>
        </revhistory>
 24   </xsl:template>
      
 26   <xsl:template match="logentry/@revision">
        <revnumber xmlns="&dbns;">
 28       <xsl:apply-templates/>
        </revnumber>
 30   </xsl:template>
      
 32   <xsl:template match="tag">
        <revremark xmlns="&dbns;">
 34       <xsl:apply-templates/>
        </revremark>
 36   </xsl:template>
      
 38   <xsl:template match="date">
        <date xmlns="&dbns;">
 40       <xsl:apply-templates/>
        </date>
 42   </xsl:template>
      
 44   <xsl:template match="author">
        <xsl:variable name="firstname" select="substring-before(., ' ')"/>
 46     <xsl:variable name="surname" select="substring-after(., ' ')"/>
        <author xmlns="&dbns;">
 48       <personname>
            <firstname><xsl:value-of select="$firstname"/></firstname>
 50         <!--<othername></othername>-->
            <surname><xsl:value-of select="$surname"/></surname>
 52       </personname>
          <email><xsl:value-of select="@email"/></email>
 54     </author>
      </xsl:template>
 56   
      <xsl:template match="msg">
 58     <revdescription xmlns="&dbns;">
          <para>
 60         <xsl:apply-templates/>
          </para>
 62     </revdescription>
      </xsl:template>
 64   
      <xsl:template match="paths">
 66     <xsl:if test="$include.paths != 0">
          <itemizedlist xmlns="&dbns;">
 68         <title>Paths</title>
            <xsl:apply-templates/>
 70       </itemizedlist>
        </xsl:if>
 72   </xsl:template>
      
 74   <xsl:template match="path">
        <listitem xmlns="&dbns;">
 76       <para>
            <xsl:apply-templates select="@action|text()"/>
 78       </para>
        </listitem>    
 80   </xsl:template>
      
 82   <xsl:template match="path/@action">
        <xsl:text>[</xsl:text>
 84     <xsl:value-of select="."/>
        <xsl:text>] </xsl:text>
 86   </xsl:template>
      <xsl:template match="path/text()">
 88     <filename xmlns="&dbns;">
          <xsl:value-of select="."/>
 90     </filename>
      </xsl:template>
 92 
      <xsl:template match="copyies">
 94     <xsl:if test="$include.paths != 0">
          <listitem xmlns="&dbns;">
 96         <title>Copies</title>
            <para>
 98           <xsl:apply-templates select="@*|text()"/>
            </para>
100       </listitem>
        </xsl:if>
102   </xsl:template>
      <xsl:template match="copy">
104     <listitem xmlns="&dbns;">
          <para>
106         <xsl:apply-templates select="@*|text()"/>
          </para>
108     </listitem>    
      </xsl:template>
110   
      <xsl:template match="copy/@source">
112     <filename xmlns="&dbns;">
          <xsl:value-of select="."/>
114     </filename>
      </xsl:template>
116   <xsl:template match="copy/text()">
        <xsl:text> -> </xsl:text>
118     <filename xmlns="&dbns;">
          <xsl:value-of select="."/>
120     </filename>
      </xsl:template>
122   
    </xsl:stylesheet>
Subversion

Subversion is similar to Mercurial: It has an --xml option to turn the log output into XML:

svn log --xml > svn-log.xml

With the -v option (verbose) you get additional path information. As the output is very similar to Mercurial, you can apply the stylesheet shown in Example 3.21, “Stylesheet hg2revhistory.xsl to Convert Mercurial XML Log Files into DocBook's revhistory also for Subversion's log file.

As an alternative, the DocBook Subversion repository (see https://docbook.svn.sourceforge.net/svnroot/docbook/trunk) contains the XSLT stylesheet releasetools/svnlog2docbook.xsl with additional features.

Discussion

TBD


[7]Theoretically you could use any of the several common attributes available on every DocBook element. The condition was the one attribute that has fitted the best in the authors mind.

Chapter 4. Print Customizations

The DocBook XSL stylesheets has got more than 200 parameters which can customize some aspects of the layout very easily (like the page dimensions). This chapter shows customizations which go beyond simple parameter change.

Currently, there is only one stylesheet available for creating FO output: fo/docbook.xsl. To be exact, this creates XSL-FO 1.1 output which is compatible with decent FO formatters.

Furthermore, the DocBook FO stylesheets supports extensions which enables the formatter to implement specific features. These features go beyond the FO specifications like PDF bookmarks, indices, etc. Currently, the stylesheets support extensions from PTC's Arbortext, Antenna House's AXF, Apache's FOP, and RenderX's XEP.

Difficulty: ★★☆ (medium)
Keywords: title page, cover, recto page, verso page, title page template

Problem

You want to design a title page of your book or article.

Solution

To design your title page there are two ways to do it, regardless if it is a book or an article:

  1. Indirectly  Write a title page template which contains the wanted elements in their respective order.

  2. Directly  Customize the specific named templates.

Both methods are shown below. Although the following descriptions focus on a book title page, the same procedure applies for an article title page as well.

Before we customize the stylesheets, we need to define, what we want to display on our title page(s). Depending on if it is a left or a right page, different elements needs to be shown. For this example, we use the following requisites:

Recto (Right) Page

This is the “main page” and the content appears in the following order:

  • the book title, from /book/title or /book/info/title

  • the book subtitle, from /book/subtitle or /book/info/subtitle

  • the book's author, from /book/info/author

  • the edition, from /book/info/edition

Verso (Left) Page

This usually holds the imprint and the content appears in the following order:

  • the book's title and subtitle in a smaller font size

  • the author, from /book/info/author

  • the edition, from /book/info/edition

  • some legal text (copyright), from /book/info/legalnotice

  • the ISBN, from /book/info/biblioid with class and the value isbn

Using Title Page Templates

To create a title page using a title page template proceed as follows:

  1. Prepare the title page template:

    1. Copy the file fo/titlepage.templates.xml from the DocBook XSL stylesheet distribution to a directory where all your FO customization is stored. Use the filename booktitlepage.xml so we know, it contains only a title page for a book.

    2. Open the file booktitlepage.xml and remove anything except the root and t:titlepage elements with the attribute t:element="book". Your title page template should look like this:

        1 <!DOCTYPE t:templates [
        2 <!ENTITY hsize0 "10pt">
          <!ENTITY hsize1 "12pt">
        4 <!ENTITY hsize2 "14.4pt">
          <!ENTITY hsize3 "17.28pt">
        6 <!ENTITY hsize4 "20.736pt">
          <!ENTITY hsize5 "24.8832pt">
        8 <!ENTITY hsize0space "7.5pt"> <!-- 0.75 * hsize0 -->
          <!ENTITY hsize1space "9pt"> <!-- 0.75 * hsize1 -->
       10 <!ENTITY hsize2space "10.8pt"> <!-- 0.75 * hsize2 -->
          <!ENTITY hsize3space "12.96pt"> <!-- 0.75 * hsize3 -->
       12 <!ENTITY hsize4space "15.552pt"> <!-- 0.75 * hsize4 -->
          <!ENTITY hsize5space "18.6624pt"> <!-- 0.75 * hsize5 -->
       14 ]>
          <t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0"
       16              xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param"
                       xmlns:fo="http://www.w3.org/1999/XSL/Format"
       18              xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
             <t:titlepage t:element="book" t:wrapper="fo:block">
       20      <!-- Content disabled for better legibility -->
             </t:titlepage>
       22 </t:templates>
  2. Customize the content of your titlepage and save your changes into the booktitlepage.xml file.

    1. Change the recto page and locate the t:titlepage-content element with its attribute t:side="recto". As definied in Recto (Right) Page, we remove everything what is not needed. Additionally we have to output edition, which we get from an empty <edition/> tag. The content of the t:titlepage-content should look like this:

        1 <t:titlepage-content t:side="recto">
        2   <title     t:named-template="division.title"
                       param:node="ancestor-or-self::book[1]"
        4              text-align="center"
                       font-size="&hsize5;"
        6              space-before="&hsize5space;"
                       font-weight="bold"
        8              font-family="{$title.fontset}"/>
            <subtitle  text-align="center"
       10              font-size="&hsize4;"
                       space-before="&hsize4space;"
       12              font-family="{$title.fontset}"/>
            <author    font-size="&hsize3;"
       14              space-before="&hsize2space;"
                       keep-with-next.within-column="always"/>
       16   <edition   font-size="&hsize3;"/>
          </t:titlepage-content>
    2. Change the verso page and locate the t:titlepage-content element with its attribute t:side="verso". As definied in Verso (Left) Page, again, we remove everything what is not needed. The content of the t:titlepage-content should look like this:

        1 <t:titlepage-content t:side="verso">
        2   <title     t:named-template="book.verso.title"
                       font-size="&hsize2;"
        4              font-weight="bold"
                       font-family="{$title.fontset}"/>
        6   <subtitle  t:named-template="book.verso.title"
                       font-size="&hsize2;"
        8              font-weight="bold"
                       font-family="{$title.fontset}"/>
       10   <author/>
            <edition/>
       12   <legalnotice/>
            <biblioid  t:predicate="[@class = 'isbn']"/>
       14 </t:titlepage-content>
    3. Leave the other elements (t:titlepage-separator and t:titlepage-before) as they are.

  3. Use the template/titlepage.xsl stylesheet from the DocBook XSL distribution to transform your booktitlepage.xml title page definition to create the booktitlepage.xsl output:

    xsltproc --output booktitlepage.xsl template/titlepage.xsl booktitlepage.xml
  4. Insert the constructed booktitlepage.xsl into your customization layer mybooktitlepage.xsl:

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <xsl:stylesheet version="1.0"
          xmlns:fo="http://www.w3.org/1999/XSL/Format"
      4   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          
      6   <xsl:import href="http://docbook.sourceforge.net/release/xsl-ns/current/fo/docbook.xsl"/>
          <xsl:include href="booktitlepage.xsl"/>
      8   <!-- More customizations hidden -->
        </xsl:stylesheet>
  5. Build your book as usual with your customization layer.

Customizing Title Pages Directly

To create a title page directly using named templates proceed as follows:

  1. Open the file fo/titlepage.templates.xsl of your DocBook XSL stylesheet distribution.

  2. Search for the correct template name(s). A template name is composed of the following components, wheras ELEMENT and SIDE are placeholders:

    ELEMENT.titlepage.SIDE

    As we want to change the title page of a book for the left (verso) and right (recto) pages, the correct template names are book.titlepage.recto and book.titlepage.verso.

  3. Create a new file, for example booktitlepage.xsl. This will contain all our customizations of our book's title page.

  4. Copy the book.titlepage.recto and book.titlepage.verso templates into your new file booktitlepage.xsl.

  5. Customize the template book.titlepage.recto according to the definitions in Recto (Right) Page:

    1. Leave the two xsl:choose conditions intact to select the book's title and subtitle.

    2. Insert after the last </xsl:choose> the following line to select the book's author from d:info/d:author:

      <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:info/d:author"/>
    3. Insert the following line to select the book's edition from d:info/d:edition:

      <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:info/d:edition"/>
    4. Remove the other xsl:apply-templates elements as we only want to display the title, subtitle, author, and the editor. The template should look like this:

        1 <xsl:template name="book.titlepage.recto">
        2   <xsl:choose>
              <xsl:when test="d:bookinfo/d:title">
        4       <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:bookinfo/d:title"/>
              </xsl:when>
        6     <xsl:when test="d:info/d:title">
                <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:info/d:title"/>
        8     </xsl:when>
              <xsl:when test="d:title">
       10       <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:title"/>
              </xsl:when>
       12   </xsl:choose>
                        
       14   <xsl:choose>
              <xsl:when test="d:bookinfo/d:subtitle">
       16       <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:bookinfo/d:subtitle"/>
              </xsl:when>
       18     <xsl:when test="d:info/d:subtitle">
                <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:info/subtitle"/>
       20     </xsl:when>
              <xsl:when test="d:subtitle">
       22       <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:subtitle"/>
              </xsl:when>
       24   </xsl:choose>
            
       26   <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:info/d:author"/>
            <xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="d:info/d:edition"/>
       28 </xsl:template>
  6. Customize the template book.titlepage.verso according to the definitions in Verso (Left) Page (note the different mode):

    1. Leave the two xsl:choose conditions intact to select the book's title and subtitle.

    2. Insert after the last </xsl:choose> the following line to select the book's author from d:info/d:author:

      <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:info/d:author"/>
    3. Insert the following line to select the book's edition from d:info/d:edition:

      <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:info/d:edition"/>
    4. Insert the following line to select some legal text from d:info/d:legalnotice:

      <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:info/d:legalnotice"/>
    5. Insert the following line to select the book's ISBN number from d:info/d:biblioid:

      <xsl:apply-templates mode="book.titlepage.verso.auto.mode"
          select="d:info/d:biblioid[@class='isbn']"/>
    6. Remove the other xsl:apply-templates elements as we only want display the title, subtitle, author, editor, legal text, and the ISBN number. The template should look like this:

        1 <xsl:template name="book.titlepage.verso">
        2   <xsl:choose>
              <xsl:when test="d:bookinfo/d:title">
        4       <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:bookinfo/d:title"/>
              </xsl:when>
        6     <xsl:when test="d:info/d:title">
                <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:info/d:title"/>
        8     </xsl:when>
              <xsl:when test="d:title">
       10       <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:title"/>
              </xsl:when>
       12   </xsl:choose>
                        
       14   <xsl:choose>
              <xsl:when test="d:bookinfo/d:subtitle">
       16       <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:bookinfo/d:subtitle"/>
              </xsl:when>
       18     <xsl:when test="d:info/d:subtitle">
                <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:info/d:subtitle"/>
       20     </xsl:when>
              <xsl:when test="d:subtitle">
       22       <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:subtitle"/>
              </xsl:when>
       24   </xsl:choose>
            
       26   <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:info/d:author"/>
            <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:info/d:editor"/>
       28   <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:info/d:legalnotice"/>
            <xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="d:info/d:biblioid[@class='isbn']"/> 
       30 </xsl:template>
  7. Insert the constructed booktitlepage.xsl into your customization layer mybooktitlepage.xsl:

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <xsl:stylesheet version="1.0"
          xmlns:fo="http://www.w3.org/1999/XSL/Format"
      4   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          
      6   <xsl:import href="http://docbook.sourceforge.net/release/xsl-ns/current/fo/docbook.xsl"/>
          <xsl:include href="booktitlepage.xsl"/>
      8   <!-- More customizations hidden -->
        </xsl:stylesheet>
  8. Build your book as usual with your customization layer.

Discussion

There are several reasons to customize a title page:

  • You want a different order of the default elements

  • You want to show or hide elements

  • You want to insert corporate logos, links, or other graphical illustrations

  • You want to distinguish between a document in draft or in final state.

All these requirements can be done, either with the direct or indirect method. Apart from your own preferences, use the direct method if you have more complicated conditions which can not be expressed by simple title page definitions. Sometimes it is faster to just add the respective named template instead of going through the indirect method.

Regardless which method you prefer, it ends up with the same named templates. For a book title page, the named templates are called in the following order, starting with book.titlepage:

book.titlepage
  book.titlepage.before.recto
  book.titlepage.recto
  book.titlepage.before.verso
  book.titlepage.verso
  book.titlepage.separator

Usually, the book.titlepage template is only customized in rare cases. For example, if you want to revamp the previous schema completely and add additional pages like half titles. Each of the templates in book.titlepage are responsible for a different setup of a title page. We discussed the book.titlepage.recto and book.titlepage.verso templates already. The templates book.titlepage.separator and book.titlepage.before.verso contain page breaks, whereas book.titlepage.before.recto is empty.

Note, all of the above templates process title page elements in a special mode. As you have seen in the section called “Customizing Title Pages Directly”, elements for a recto page are processed in the book.titlepage.recto.auto.mode mode. The same principle applies for a verso page and its mode book.titlepage.verso.auto.mode. However, not all elements have a template with such modes as not all elements can (and should) appear on a title page. Look into the file fo/titlepage.templates.xsl to see which are definied. Assume title and subtitle have already templates for recto and verso pages as well as all the elements which are listed in the original book.titlepage.verso and book.titlepage.recto.

For example, the edition element has certainly no templates for a recto and verso book title page. If you do not have definied one, a fallback mechanism takes place. For this reason, if you call a element in book.titlepage.verso and book.titlepage.recto, you need also to define the respective templates:

  1 <xsl:template match="d:edition" mode="book.titlepage.recto.auto.mode">
  2    <!-- Add your code for a recto page -->
    </xsl:template>
  4     
    <xsl:template match="d:edition" mode="book.titlepage.verso.auto.mode">
  6    <!-- Add your code for a verso page -->
    </xsl:template>

Usually, you want to display the edition on a recto page different than on a verso page.

See Also

http://www.sagehill.net/docbookxsl/HTMLTitlePage.html

Difficulty: ★★☆ (medium)
Keywords: title page, style title page

Problem

You do not want to overhaul the default title pages, but you want to change small things, like the font size, margins, or other stylistic parameters.

Solution

The difficulty is to find the correct template to customize. Here is a general procedure how to do this:

Finding the Correct Template to Customize for a Title Page
  1. Open the file fo/titlepage.templates.xsl from your DocBook XSL distribution.

  2. Determine the following parameters and write it down or memorize it:

    • The title page which you want to customize (usually something like book, chapter, etc.), refered as DIVISION

    • The element on that title page, referred as ELEMENT

    • The side, be it recto (right) or verso (left), refered as SIDE.

  3. Compose a template in your mind from the previous parameters and replace the placeholders:

    <xsl:template match="ELEMENT" mode="DIVISION.titlepage.SIDE.auto.mode">
  4. Try to find the template from Step 3 in fo/titlepage.templates.xsl.

  5. If you have found the template depicted in Step 3, copy it to your customization layer. If there is no such template, create a new one with the same signature.

  6. Customize the template.

  7. Build your document with your customization layer.

Discussion

To make the general explanations a bit more useful, here is a small example: you want to change the font size for the title of a book's recto title page. Applying Finding the Correct Template to Customize for a Title Page leads to the following template:

<xsl:template match="d:title" mode="book.titlepage.recto.auto.mode">

After you have copied it to your customization layer, you can change the font-size (marked bold):

  1 <xsl:template match="d:title" mode="book.titlepage.recto.auto.mode">
  2   <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" 
         xsl:use-attribute-sets="book.titlepage.recto.style" 
  4      text-align="center" 
         font-size="40pt"
  6      space-before="18.6624pt" 
         font-weight="bold" 
  8      font-family="{$title.fontset}">
        <xsl:call-template name="division.title">
 10       <xsl:with-param name="node" select="ancestor-or-self::d:book[1]"/>
        </xsl:call-template>
 12   </fo:block>
    </xsl:template>

In the previous example, the font size was changed from the original value of 24.8832pt to 40pt. The other objects are unchanged. Other attributes can be changed as needed.

See Also

Section 4.2, “Designing a Title Page”

Difficulty: ★☆☆ (easy)
Keywords: line height, leading, half-leading, font size

Tony Graham

Problem

You want to change the leading between consecutive lines of text.

Solution

Leading is the distance from one baseline to the next, or in other words, the “interlinear space.” It is not the same as the line height. Unfortunately, the FO specification named the property for influencing the leading line-height which makes it confusing.

The DocBook stylesheets introduce the parameter line-height with the same name and functionality. It acts as a placeholder for the above line-height property. The following examples do all the same (except for the value normal). It is assumed, you have a base font size of 10pt; negative values in line-height are not allowed:

normal

This is the default value. The real value is set by the formatter and depends on the font size, usually it is a value between 1.0 and 1.2.

Say more about the real value

Length

Sets the line height of the respective value:

<xsl:param name="line-height">12pt</xsl:param>

The leading is 2pt (12pt − 10pt).

Number

Sets the line height is the result of the value multiplied by the font size:

<xsl:param name="line-height">1.2</xsl:param>
Percentage

Sets the line height is the result of the percentage value multiplied by the font size:

<xsl:param name="line-height">120%</xsl:param>

Discussion

Unfortunately, the situation with line height in FO is a bit more complicated as it first seems. Usually, this is what most people expects:

  1 First line
  2  [Gap]
    Second Line
  4  [Gap]
    Third Line
  6  [Gap]

However, the line-height property is a “half-leading” value which are added before and after a line. This leads to the more realistic picture:

  1  [1/2 Gap]
  2 First line
     [1/2 Gap]
  4  [1/2 Gap]
    Second Line
  6  [1/2 Gap]
     [1/2 Gap]
  8 Third Line
     [1/2 Gap]

If the line height is constant in each line, the effect is the same (except at the top or bottom of a reference area). According to the FO specification of line-height the FO property is a compound datatype which has minimum, optimum, maximum, conditionally, and precedence. The minimum, optimum, and maximum constraints are length

That said, leading has a direct influence on how easy a text is read. If the value is too small, consecutive lines gets overlapped. If the value is too big, the cohersion of text gets lost. Most text requires positive leading. Usually 9pt/11pt, 10pt/12pt, 11pt/13pt, and 12pt/15pt are the most common (the two values depicting the font size and line height).

According to Robert Bringhurst in his book The Elements of Typographic Style he recommends more lead in the following situations (cited from his book from page 37):

  • Dark faces need more lead than light ones

  • Large-bodied faces need more lead than smaller-bodied ones

  • Unserifed faces often need more lead (or a shorter line) than their serifed counterparts

  • Text with thickened by superscripts, subscripts, mathematical expressions, or the frequent use of full capitals

See Also

Difficulty: ★★☆ (medium)
Keywords: hyphenation, URLs, zero width space, soft hyphen

Problem

You have URLs or paths which you want to hyphenate correctly. The URLs have to break on slashes or other characters only, but not between words.

Solution

The hyphenation of URLs in the DocBook stylesheets are controlled by two parameters: ulink.hyphenate and ulink.hyphenate.chars. The first parameter, if not empty, turns on hyphenation. Specify a hyphenation character, usually either a Unicode soft hyphen (U+00AD) or a Unicode zero-width space (U+200B).

The second parameter, ulink.hyphenate.chars, let you define your allowable hyphenation points. The default value is a slash (/), but URLs can contain more characters where it is desirable to hyphenate. For this reason, the DocBook parameter reference recommends the following value:

<xsl:param name="ulink.hyphenate.chars">:/@&?.#</xsl:param

Discussion

The easiest way is to set the parameters ulink.hyphenate.chars and ulink.hyphenate to the values showed in the last section and be happy. However, for professional needs, this is not enough. The parameters and embedded algorithm do not take into account protocols, for example http. Protocols begin with the schema followed by :// as in http://. In some situations (although rare), a hyphenation can occur between the double slashes or before the colon. Furthermore, according to the Chicago Manual of Style, it is desirable to distinguish characters before and after the hyphenation takes place.

All these requirements are implemented in the stylesheet showed in Example 4.1, “hyphenate-url.xsl. It cuts off the protocol with its :// and iterates through each characters and checks, if a hyphenation point needs to be inserted before or after it.

Example 4.1. hyphenate-url.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  4     xmlns:fo="http://www.w3.org/1999/XSL/Format">
    
  6 <xsl:template name="hyphenate-url">
      <xsl:param name="url" select="''"/>
  8 
      <!-- Remove the "schema://" prefix, so it disturbs not the
 10        algorithm in "hyphenate-url-string" -->
      <xsl:choose>
 12    <xsl:when test="$ulink.hyphenate = ''">
          <xsl:value-of select="$url"/>
 14    </xsl:when>
       <xsl:when test="contains($url, '://')">
 16       <xsl:value-of select="substring-before($url, '://')"/>
          <xsl:text>://</xsl:text>
 18       <xsl:copy-of select="$ulink.hyphenate"/>
          <xsl:call-template name="hyphenate-url-string">
 20         <xsl:with-param name="url" select="substring-after($url, '://')"/>
          </xsl:call-template>
 22    </xsl:when>
       <xsl:otherwise>
 24       <xsl:call-template name="hyphenate-url-string">
            <xsl:with-param name="url" select="normalize-space($url)"/>
 26       </xsl:call-template>
       </xsl:otherwise>
 28   </xsl:choose>
    </xsl:template>
 30 
    
 32 <xsl:template name="hyphenate-url-string">
      <xsl:param name="url" select="''"/>
 34   <xsl:variable name="char" select="substring($url, 1,1)"/>
    
 36   <xsl:choose>
       <xsl:when test="$url=''"/>
 38    <!-- Insert breakpoint _before_ the character -->
       <xsl:when test="contains($ulink.hyphenate.before.chars, $char)">
 40      <xsl:value-of select="concat($ulink.hyphenate, $char)"/>
         <xsl:call-template name="hyphenate-url-string">
 42        <xsl:with-param name="url" select="substring($url, 2)"/>
         </xsl:call-template>
 44    </xsl:when>
       <!-- Insert breakpoint _after_ the character -->
 46    <xsl:when test="contains($ulink.hyphenate.after.chars, $char)">
         <xsl:value-of select="concat($char, $ulink.hyphenate)"/>
 48      <xsl:call-template name="hyphenate-url-string">
           <xsl:with-param name="url" select="substring($url, 2)"/>
 50      </xsl:call-template>
       </xsl:when>
 52    <xsl:otherwise>
         <xsl:value-of select="$char"/>
 54      <xsl:call-template name="hyphenate-url-string">
           <xsl:with-param name="url" select="substring($url, 2)"/>
 56      </xsl:call-template>
       </xsl:otherwise>
 58   </xsl:choose>
    </xsl:template>
 60 </xsl:stylesheet>

Include the above stylesheet into your customization layer with additionally the following parameters:

  1 <!-- Insert breakpoint /before/ the following characters: -->
  2 <xsl:param name="ulink.hyphenate.before.chars"
      >.,%?&amp;#\-+{_</xsl:param>
  4 <!-- Insert breakpoint /after/ the following characters: -->
    <xsl:param name="ulink.hyphenate.after.chars"
  6   >/:@=};</xsl:param>
Difficulty: ★☆☆ (easy)
Keywords: initials, drop caps, floats

Problem

You need a “drop cap”, or Initial, which is a “a letter at the beginning of a work, a chapter, or a paragraph that is larger than the rest of the text.

Solution

Typographically, you have different options to place initials:

  • on the same baseline as the first line of text,

  • as floats, embedded between two or more lines,

  • besides the left margin of the text block without indentation.

Additionally you can design your initials as graphics, but we will come to this later.

Place Initials on the Same Baseline

This is the easiest method to implement. The stylesheet normalizes the text node of the first paragraph, extract the first character and wrap it between an fo:inline element with font size, family, and weight:

Example 4.2. initials-baseline.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:fo="http://www.w3.org/1999/XSL/Format"
  4   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      
  6   <xsl:param name="drop.caps.size">20pt</xsl:param>
      <xsl:param name="drop.caps.font-family" select="$body.font.family"/>
  8   <xsl:param name="drop.caps.font-weight">bold</xsl:param>
      
 10   <xsl:template name="create.initial">
        <xsl:param name="initial" select="substring(normalize-space(.),1,1)"/>
 12     <fo:inline>
          <fo:inline font-size="{$drop.caps.size}"
 14         font-weight="{$drop.caps.font-weight}"
            font-family="{$drop.caps.font-family}">
 16         <xsl:copy-of select="$initial"/>
          </fo:inline>
 18       <xsl:value-of select="substring(normalize-space(.), 2)"/>
        </fo:inline>
 20   </xsl:template>
    </xsl:stylesheet>

To use it, include it into your customization layer. It is usually called in text nodes like the first paragraph from a section which parent is an article:

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <!DOCTYPE xsl:stylesheet 
    [
  4  <!ENTITY db "http://docbook.sourceforge.net/release/xsl-ns/current"> 
    ]>
  6 <xsl:stylesheet version="1.0"
      xmlns:d="http://docbook.org/ns/docbook"
  8   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      
 10   <xsl:import href="&db;/fo/docbook.xsl"/>
      <xsl:include href="initials-baseline.xsl"/>
 12   
      <xsl:template match="d:article/d:section/d:para[1]/text()">
 14     <xsl:call-template name="create.initial"/>
      </xsl:template>
 16 </xsl:stylesheet>

It is easy to extend it to chapters, you just have to copy the template and correct the content in the match attribute to:

<xsl:template match="d:chapter/d:section/d:para[1]/text()">
Implement Initials as Floats

TBD

Place Initials in Left Margin

TBD

Discussion

The solution described in the section called “Place Initials on the Same Baseline” is in most cases sufficient. However, if the first character is not a letter, any character is incorrectly made an initial.

See Also

Find information about the property line-height in Section 4.4, “Influencing the Leading”.

Difficulty: ★☆☆ (easy)
Keywords: titles, numbering, appendix.autolabel, chapter.autolabel, part.autolabel, preface.autolabel, qandadiv.autolabel, reference.autolabel, section.autolabel, section.label.includes.component.label, component.label.includes.part.label, label.from.part, section.autolabel.max.depth

Problem

You want a number in front of your structural elements like appendix, chapter, section, etc.

Solution

The DocBook XSL stylesheets provide already a decent numbering scheme for high level divisions like parts, appendices, chapters, and references. The most common use is numbering section. If you want to automatically number section titles, set the section.autolabel parameter either manually or through a customization layer, for example:

<xsl:param name="section.autolabel" select="1"/>

Discussion

The DocBook XSL stylesheets contain autolabel parameters for the common elements appendix, chapter, part, preface, qandadiv, reference, and section. These can be set individually to change the numbering of for the same elements. The default values are shown in Table 4.1, “Autolabel Parameters and their Default Values”.

Table 4.1. Autolabel Parameters and their Default Values
Parameter Default Example
appendix.autolabel A Appendix A. Python 3
chapter.autolabel 1 Chapter 1. A Tutorial Introduction
part.autolabel I Part I. The Python Language
preface.autolabel 0 Prefaces are usually not numbered
qandadiv.autolabel 1 3.1 Installation Questions
reference.autolabel I I. Python Reference
section.autolabel 0 Not numbered by default

The autolabel parameters can contain the following values:

Value 0

A value of zero disables the automatic numbering. For example, if you want to disable automatic numbering for appendix elements, use this:

<xsl:param name="appendix.autolabel" select="0"/>
Value 1

A value of one enables the automatic numbering and uses arabic numerals. For example, section numbering is disabled by default. Use the code in the Solution section.

String

A string enables a different automatic numbering schema, for example roman numerals. See the following table to get an overview.

Table 4.2. Possible Formats for Autolabel Parameters
Value Alternative Value Style Example
1 arabic Arabic numerals 1, 2, 3, 4, …
I upperroman Uppercase roman numerals I, II, III, IV, …
i lowerroman Lowercase roman numerals i, ii, iii, iv, …
A upperalpha Uppercase letters A, B, C, D, …
a loweralpha Lowercase letters a, b, c, d, …
&#x661; arabicindic Arabic-Indic numerals ١, ٢, ٣, ٤, …

Mostly you will probably want sections to be numbered including its parent numbering. If you do not touch chapter.autolabel, use the parameter section.label.includes.component.label and set it to 1:

<xsl:param name="section.autolabel" select="1"/>
<xsl:param name="section.label.includes.component.label" select="1"/>

With the following parameters you can further customize your numbering:

component.label.includes.part.label

Controls if appendix or chapter number labels are prefixed with their contained part label.

label.from.part

Defines if the components inside a part is renumbered or not. A value of non-zero restarts the chapter number and counts again from one. Use this numbering if you want unambiguous numerals.

The value zero (the default) restarts the component number throughout each book.

section.autolabel.max.depth

Controls which sections get a number. By default, all sections are get numbered (default value is 8.) If you want to number only sections at level 1, set the parameter to the value 1.

Let us assume the following structure in a book:

  1 Part: The Python Language
  2   Chapter: A Tutorial Introduction
         Section: Running Python
  4      Section: Variables
    
  6   Chapter: Lexical Conventions and Syntax
         Section: Line Structure and Indentation
  8      Section: Identifiers and Reserved Words
    
 10 Part: The Python Library
      Chapter: Build-In Functions
 12      Section: Build-In Functions and Types
         Section: Build-In Exceptions
 14   Chapter: Python Runtime Services
         Section: atext
 16      Section: copy
Table 4.3. Parameter Combinations
Parameters Result
No parameters set, using the default settings
I. The Python Language
  1. A Tutorial Introduction
      Running Python
      Variables
  2. Lexical Conventions and Syntax
      Line Structure and Indentation
      Identifiers and Reserved Words
II. The Python Library
  3. Build-In Functions
      Build-In Functions and Types
      Build-In Exceptions
  4. Python Runtime Services
      atext
      copy
section.autolabel=1
I. The Python Language
  1. A Tutorial Introduction
      1. Running Python
      2. Variables
  2. Lexical Conventions and Syntax
      1. Line Structure and Indentation
      2. Identifiers and Reserved Words
II. The Python Library
  3. Build-In Functions
      1. Build-In Functions and Types
      2. Build-In Exceptions
  4. Python Runtime Services
      1. atexit
      2. copy
section.autolabel=1
section.label.includes.component.label=1
I. The Python Language
  1. A Tutorial Introduction
      1.1. Running Python
      1.2. Variables
  2. Lexical Conventions and Syntax
      2.1. Line Structure and Indentation
      2.2. Identifiers and Reserved Words
II. The Python Library
  3. Build-In Functions
      3.1. Build-In Functions and Types
      3.2. Build-In Exceptions
  4. Python Runtime Services
      4.1. atexit
      4.2. copy
section.autolabel=1
section.label.includes.component.label=1
component.label.includes.part.label
I. The Python Language
  I.1. A Tutorial Introduction
      I.1.1. Running Python
      I.1.2. Variables
  I.2. Lexical Conventions and Syntax
      I.2.1. Line Structure and Indentation
      I.2.2. Identifiers and Reserved Words
II. The Python Library
  II.3. Build-In Functions
      II.3.1. Build-In Functions and Types
      II.3.2. Build-In Exceptions
  II.4. Python Runtime Services
      II.4.1. atexit
      II.4.2. copy
section.autolabel=1
section.label.includes.component.label=1
component.label.includes.part.label
label.from.part=1
I. The Python Language
  I.1. A Tutorial Introduction
      I.1.1. Running Python
      I.1.2. Variables
  I.2. Lexical Conventions and Syntax
      I.2.1. Line Structure and Indentation
      I.2.2. Identifiers and Reserved Words
II. The Python Library
  II.1. Build-In Functions
      II.1.1. Build-In Functions and Types
      II.1.2. Build-In Exceptions
  II.2. Python Runtime Services
      II.2.1. atexit
      II.2.2. copy

However, when dealing with other numbering systems, the above parameters are not enough. To support, for example, Japanese numbering, you need to customize the named template autolabel.format from common/labels.xsl.

Example 4.3. Extending autolabel.format
  1 <xsl:template name="autolabel.format">
  2   <xsl:param name="context" select="."/>
      <xsl:param name="format"/>
  4 
      <xsl:choose>
  6     <xsl:when test="string($format) != 0">
          <xsl:choose>
  8         <xsl:when test="string($format)='001'">
              <xsl:value-of select="$format"/>
 10         </xsl:when>
            <xsl:when test="$format='loweralpha' or $format='a'">
 12           <xsl:value-of select="'a'"/>
            </xsl:when>
 14         <xsl:when test="$format='lowerroman' or $format='i'">
              <xsl:value-of select="'i'"/>
 16         </xsl:when>
            <xsl:when test="$format='upperalpha' or $format='A'">
 18           <xsl:value-of select="'A'"/>
            </xsl:when>
 20         <xsl:when test="$format='upperroman' or $format='I'">
              <xsl:value-of select="'I'"/>
 22         </xsl:when>
            <xsl:when test="$format='arabicindic' or $format='١'">
 24           <xsl:value-of select="'١'"/>
            </xsl:when>
 26         <xsl:when test="$format='japanese' or $format='&#x4e00;'">
              <xsl:value-of select="'&#x4e00;'"/>
 28         </xsl:when>
            <xsl:otherwise>
 30           <xsl:message>
                <xsl:text>Unexpected </xsl:text>
 32             <xsl:value-of select="local-name(.)"/>
                <xsl:text>.autolabel value: </xsl:text>
 34             <xsl:value-of select="$format"/>
                <xsl:text>; using default.</xsl:text>
 36           </xsl:message>
              <xsl:call-template name="default.autolabel.format"/>
 38         </xsl:otherwise>
          </xsl:choose>
 40     </xsl:when>
      </xsl:choose>
 42 </xsl:template>

Unfortunately, the xsltproc processor does not support this currently (as in version 1.1.24). Only Saxon does it correct.

See Also

Chapter 5. (X)HTML Customizations

HTML is a very important output format for the DocBook XSL stylesheets as it is not only displayed on Web sites, but also used “inside” ebooks (EPUB). It comes in several derivates.

Currently, there are several HTML derivates available as target formats. As such, “the” HTML does not exist, only a variety of HTML dialects:

Table 5.1. Overview of Different HTML Stylesheets
Directory Explanation
html/ Contains stylesheets for the “classicalHTML 4.
htmlhelp/ Contains stylesheets for HTMLHelp, the standard help system from Windows 3.0 through Windows XP. The main stylesheet htmlhelp.xsl uses code from the HTML 4.x stylesheets
webhelp/ Contains the result of the GSOC 2010 and creates a Web page with a sidebar, search form, and hierarchical navigation. The stylesheet incorporates the XHTML stylesheets.
website/ Contains stylesheets to create a “Web site
xhtml/ Contains stylesheets for XHTML 1.0 (“transitional XHTML”). These stylesheets are generated through a XSLT transformation from the HTML core stylesheets
xhtml-1_1/ Contains stylesheets for XHTML 1.1. Like the one for XHTML, they are generated through a XSLT transformation. In comparison, the XHTML 1.1 omits certain attributes which were allowed in XHTML or HTML. The missing part must be implemented by CSS. The XHTML 1.1 stylesheets are also used for EPUB creation.
xhtml5/ Contains stylesheets for HTML 5. These stylesheets customizes the XHTML stylesheets. As such it inherits all the features and parameters. The HTML 5 stylesheets are also used for EPUB3 creation.
Difficulty: ★★☆ (medium)
Keywords: table of contents, TOC, authors, proceedings

Problem

You have a document which is written by different authors (like in proceedings) and want to include the author names in the table of contents.

Solution

You need to customize the toc.line template. Proceed as follows:

  1. Make sure your chapters, appendices, sections, etc. contain at least one author, like in the following example:

      1 <sect1>
      2   <title>How to Become a Linux Mascott</title>
          <info>
      4     <author>
              <personname>
      6         <firstname>Tux</firstname>
                <surname>Penguin</surname>
      8       </personname>
            </author>
     10   </info>
          <!-- ... -->
     12 </sect1>
  2. Create a customization layer first as shown in Section 2.3, “Writing Customization Layers”.

  3. Add the following line to your customization layer:

    <xsl:include href="autotoc.xsl"/>
  4. Create a new file autotoc.xsl in the same directory, with the following contents:

      1 <xsl:stylesheet version="1.0"
      2   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          xmlns="http://www.w3.org/1999/xhtml">
      4   
          <xsl:template name="toc.line">
      6     <xsl:param name="toc-context" select="."/>
            <xsl:param name="depth" select="1"/>
      8     <xsl:param name="depth.from.context" select="8"/>
        
     10     <xsl:variable name="author" select="*/author|*/authorgroup/author"/> 1
        
     12     <xsl:if test="$author">                                2
              <span class="author">
     14         <xsl:call-template name="person.name.list">        3
                  <xsl:with-param name="person.list" select="$author"/>
     16         </xsl:call-template>
                <xsl:text>: </xsl:text>
     18       </span>
            </xsl:if>
     20     <span class="{local-name(.)}">                         4
              <xsl:if test="$autotoc.label.in.hyperlink = 0">
     22         <xsl:variable name="label">
                  <xsl:apply-templates select="." mode="label.markup"/>
     24         </xsl:variable>
                <xsl:copy-of select="$label"/>
     26         <xsl:if test="$label != ''">
                  <xsl:value-of select="$autotoc.label.separator"/>
     28         </xsl:if>
              </xsl:if>
     30 
              <a>
     32         <xsl:attribute name="href">
                  <xsl:call-template name="href.target">
     34             <xsl:with-param name="context" select="$toc-context"/>
                    <xsl:with-param name="toc-context" select="$toc-context"/>
     36           </xsl:call-template>
                </xsl:attribute>
     38 
                <xsl:if test="not($autotoc.label.in.hyperlink = 0)">
     40           <xsl:variable name="label">
                    <xsl:apply-templates select="." mode="label.markup"/>
     42           </xsl:variable>
                  <xsl:copy-of select="$label"/>
     44           <xsl:if test="$label != ''">
                    <xsl:value-of select="$autotoc.label.separator"/>
     46           </xsl:if>
                </xsl:if>
     48 
                <xsl:apply-templates select="." mode="titleabbrev.markup"/>
     50       </a>
            </span>
     52   </xsl:template>
        </xsl:stylesheet>

    1 

    Collects all author nodes regardless if they appear in info or authorgroup

    2 

    Checks, if author nodes were found

    3 

    Calls person.name.list and pass the nodes from 1

    4 

    Contains the original code from autotoc.xsl and creates the title entry for the table of contents

  5. Rebuild your document with your customization layer.

When you process the above section with the customization layer, you will receive the following line:

Tux Penguin: How to Become a Linux Mascott

Or in HTML notation:

  1 <span class="author">Tux Penguin: </span>
  2 <span class="section">
      <a href="...">How to Become a Linux Mascott</a> 
  4 </span>

Depending on the parameter section.autolabel the title can be prefixed with a number.

Discussion

The previous stylesheet works also for one or more authors. It does not matter if the author elements appear as a direct child of info or authorgroup. The following code produces the same string:

  1 <info>
  2   <author>
        <personname>
  4       <firstname>Tux</firstname>
          <surname>Penguin</surname>
  6     </personname>
      </author>
  8   <author>
        <personname>
 10       <firstname>Wilber</firstname>
          <surname>Gimp</surname>
 12     </personname>
      </author>
 14 </info>
  1 <info>
  2   <authorgroup>
        <author>
  4       <personname>
            <firstname>Tux</firstname>
  6         <surname>Penguin</surname>
          </personname>
  8     </author>
        <author>
 10       <personname>
            <firstname>Wilber</firstname>
 12         <surname>Gimp</surname>
          </personname>
 14     </author>
      </authorgroup>
 16 </info>

Even if you mix author and authorgroup you will get the correct string output.

You can also use elements other than author. To detect editor, extend the variable author as follows:

<xsl:variable name="author"
      select="*/author|*/editor|*/authorgroup/author|*/authorgroup/editor"/>

See Also

Difficulty: ★★☆ (medium)
Keywords: HTML, simple navigation, next, previous, sections, generate.simple.navigation

Problem

You need a simple navigation for your single HTML file. The navigation should contain for each chapter a link to the next and previous chapters including an up link pointing to the enclosing part or book. This is depicted in the following graphic:

Solution

The following file defines the named template generate.simple.navigation:

Example 5.2. simple-navigation.xsl
  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  4   xmlns:d="http://docbook.org/ns/docbook"
      xmlns="http://www.w3.org/1999/xhtml"
  6   exclude-result-prefixes="d">
        
  8   <xsl:template name="generate.simple.navigation">
        <xsl:param name="node" select="."/>
 10     <xsl:variable name="prev" select="$node/preceding-sibling::d:chapter"/>
        <xsl:variable name="next" select="$node/following-sibling::d:chapter"/>
 12     <xsl:variable name="up"   select="$node/parent::d:*"/>
       
 14     <div class="chapter-navigation">
          <ul>
 16         <xsl:if test="count($next) >0">
              <li class="next">
 18             <xsl:call-template name="gentext.nav.next"/>
                <xsl:text>: </xsl:text>
 20             <a>
                  <xsl:attribute name="href">
 22                 <xsl:call-template name="href.target">
                      <xsl:with-param name="object" select="$next"/>
 24                 </xsl:call-template>
                  </xsl:attribute>
 26               <xsl:value-of select="$next/d:title"/>
                </a>
 28           </li>
            </xsl:if>
 30         <xsl:if test="count($prev) >0">
              <li class="prev">
 32             <xsl:call-template name="gentext.nav.prev"/>
                <xsl:text>: </xsl:text>
 34             <a>
                  <xsl:attribute name="href">
 36                 <xsl:call-template name="href.target">
                      <xsl:with-param name="object" select="$prev"/>
 38                 </xsl:call-template>
                  </xsl:attribute>
 40               <xsl:value-of select="$prev/d:title"/>
                </a>
 42           </li>
            </xsl:if>
 44         <xsl:if test="count($up) >0">
              <li class="up">
 46             <xsl:call-template name="gentext.nav.up"/>
                <xsl:text>: </xsl:text>
 48             <a>
                  <xsl:attribute name="href">
 50                 <xsl:call-template name="href.target">
                      <xsl:with-param name="object" select="$up"/>
 52                 </xsl:call-template>
                  </xsl:attribute>
 54               <xsl:value-of select="$up/d:title"/>
                </a>
 56           </li>
            </xsl:if>
 58       </ul>
        </div>
 60   </xsl:template>
    </xsl:stylesheet>

This is not enough, of course. Use the following steps to include it into your customization layers:

  1. Create a customization layer as shown in Section 2.3, “Writing Customization Layers”.

  2. Include the stylesheet from Example 5.2, “simple-navigation.xsl into your customization layer:

    Example 5.3. db-simple-navigation.xsl
      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <!DOCTYPE xsl:stylesheet [
          <!ENTITY db "http://docbook.sourceforge.net/release/xsl-ns/current">
      4 ]>
        <xsl:stylesheet version="1.0"
      6   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          xmlns:d="http://docbook.org/ns/docbook"
      8   xmlns="http://www.w3.org/1999/xhtml" 
          exclude-result-prefixes="d">
     10   
          <xsl:import href="&db;/xhtml/docbook.xsl"/>
     12   <xsl:import href="simple-navigation.xsl"/>
          
     14   <xsl:param name="generate.simple.navigation" select="1"/>
          <xsl:param name="html.stylesheet">book.css</xsl:param>
     16 
          <xsl:template name="chapter.titlepage.before.recto">
     18     <xsl:if test="$generate.simple.navigation != 0">
              <xsl:call-template name="generate.simple.navigation"/>
     20     </xsl:if>
          </xsl:template>
     22 </xsl:stylesheet>
  3. Use the file db-simple-navigation.xsl to transform your documents.

If you want to switch on or off the above behaviour, use the parameter generate.simple.navigation[8] and set it to 0.

Discussion

The named template generate.simple.navigation works as follows:

  1. Three variables are definied for the previous, next, and up links. All depends on the node parameter which is by default the context node. This is useful as you can change the behaviour very easily by just changing the context node when calling the template with xsl:call-template.

  2. The prev and next variables are filled with the previous or next chapter elements along their sibling axis. In comparison, the up variable needs to find its enclosing element; it uses the parent axis for this purpose.

    If there are no previous or next chapters, the node set will be empty. For the up variable, this depends on where a chapter belongs; usually it is enclosed in a book or part element. As we need only the parent element As such this variable can not be empty (only if the chapter would be the root element.)

  3. The simple navigation is implemented as a unordered list inside a div element. The enclosing div element is used to make styling with CSS easier.

  4. With xsl:if we check the amount of nodes in our prev and next variables. Only if the variable contains more than zero nodes it will a listitem created.

  5. If we create a listitem, we want to insert a text to help our readers and to distinguish the different directions. The text has to be independent from the used language; so hard-coding the text would not be sufficient. For this reason, the DocBook stylesheets contains named templates to generate localized text. The next, previous, and up link texts are created through the named templates generate.nav.next, generate.nav.prev, and generate.nav.up.

  6. As the generated localized text contains only the text without interpunctations, we append “: ”.

  7. We create the link with the a link. The needed href attribute is created by calling href.target (origin html.xsl). This template is responsible for the correct linking value.

  8. The content of the a element is inserted from the title element of the corresponding node. As we are only interested in the string value, we can use xsl:value-of.

The generate.simple.navigation template matches only chapters along the sibling axis. As such it can not find a glossary or appendix after a chapter. If you want to create links for any component elements, not only chapters, you need to change the variables prev and next. A first attempt would lead to this:

<xsl:variable name="prev" select="$node/preceding-sibling::d:*[1]"/>
<xsl:variable name="next" select="$node/following-sibling::d:*[1]"/>

This works for the next variables. However, our expression for the prev variable contains a bug. Consider the following structure:

  1 book
  2   title
      info
  4   chapter
      ...

The preceding-sibling axis returns the info and title elements. This is not what you want as these are no component elements for our prev link. In that case we need an expression to filter out the unwanted elements. This is done with an predicate:

<xsl:variable name="prev" select="$node/preceding-sibling::d:*[not(self::d:title|self::d:info)][1]"/>

That expression first creates a node set with all preceding elements. In a second step they are check against the term not(self::d:title|self::d:info); only those elements remain in the node set which are not title or info elements. In our above example, this leads to a node set with zero nodes and is exactly what we wanted to achieve.

With the previous change, we allow any structural element to be included in a next or previous link. However, we show our navigation links only in chapter titlepages at the moment (the named template chapter.titlepage.before.recto.) We need to extend the stylesheet db-simple-navigation.xsl to allow elements like appendix, glossary, etc. Refer to the content modell of DocBook´s book element for details. For an appendix this looks like this:

  1 <xsl:template name="appendix.titlepage.before.recto">
  2   <xsl:if test="$generate.simple.navigation != 0">
        <xsl:call-template name="generate.simple.navigation"/>
  4   </xsl:if>
    </xsl:template>

For the other elements this is exactly the same except the name. Just use the element name and append .titlepage.before.recto.

Difficulty: ★★☆ (medium)
Keywords: breadcrumbs, navigation

Problem

You want to display a “path” to your current chapter, section etc. to improve fast jumping to parent structures.

Solution

Use breadcrumbs[9] to improve navigation. Use the following procedure to create breadcrumbs for your documents:

  1. Create a customization layer as shown in Section 2.3, “Writing Customization Layers”.

  2. Create a file breadcrumbs.xsl with the following content:

      1 <xsl:stylesheet version="1.0"
      2   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          xmlns:d="http://docbook.org/ns/docbook"
      4   xmlns="http://www.w3.org/1999/xhtml"
          exclude-result-prefixes="d">
      6 
          <xsl:param name="breadcrumbs.separator" select="' > '"/> 1
      8 
          <xsl:template name="generate.breadcrumbs">
     10     <xsl:param name="current.node" select="."/>
            <div class="breadcrumbs">
     12       <xsl:for-each select="$current.node/ancestor::*">    2
                <span class="breadcrumb-link">
     14           <a>
                    <xsl:attribute name="href">                    3
     16               <xsl:call-template name="href.target">
                        <xsl:with-param name="object" select="."/>
     18                 <xsl:with-param name="context" select="$current.node"/>
                      </xsl:call-template>
     20             </xsl:attribute>
                    <xsl:apply-templates select="." mode="title.markup"/> 4
     22           </a>
                </span>
     24         <xsl:copy-of select="$breadcrumbs.separator"/>     5
              </xsl:for-each>
     26       <!-- Display the current node, but not as a link -->
              <span class="breadcrumb-node">                       6
     28         <xsl:apply-templates select="$current.node" mode="title.markup"/>
              </span>
     30     </div>
          </xsl:template>
     32 </xsl:stylesheet>

    1 

    Parameter to separate each component

    2 

    Iterates over the ancestor axis

    3 

    Creates the href attribute by calling href.target to create appropriate link references even for chunked output

    4 

    Inserts the processed title

    5 

    Inserts the breadcrumbs separator

    6 

    Inserts the processed title of the current node but not as a link

  3. Include breadcrumbs.xsl into your customization layer from Step 1:

    <xsl:include href="breadcrumbs.xsl"/>
  4. Add the following code into your customization layer:

      1 <xsl:template name="user.header.content">
      2   <xsl:call-template name="generate.breadcrumb"/>
        </xsl:template>
  5. Build your document with your customization layer.

For example, consider the the current topic. It is embedded into this nested structure:

  1 book: The DoCookBook
  2   chapter: (X)HTML Customizations
         sect1: Implementing “Breadcrumbs”

The above breadcrumbs.xsl stylesheets creates this HTML code when the current node is this topic:

  1 <div class="breadcrumbs">
  2   <span><a href="...X...">The DoCookBook</a></span>
      >
  4   <span><a href="...Y...">(X)HTML Customizations</a></span>
      >
  6   <span class="breadcrumb-node">Implementing “Breadcrumbs”</span>  
    </div>

Leading to the following appearance:

The DoCookBook > (X)HTML Customizations > Implementing “Breadcrumbs”

Whereas all spans contains links to their respective components except the last one.

Discussion

TBD

See Also

Difficulty: ★★☆ (medium)
Keywords: TOC, table of contents

Problem

You have a book and want the table of contents appear after the main content.

Solution

The processing of a book is handled in the xhtml/division.xsl file. The template needs to be copied and inserted in your customization layer. To move your table of contents, do the following:

  1. Create a customization layer as shown in Section 2.3, “Writing Customization Layers”.

  2. Create a file move-toc.xsl with the following content:

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <xsl:stylesheet  version="1.0"
          xmlns="http://www.w3.org/1999/xhtml"
      4   xmlns:d="http://docbook.org/ns/docbook"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      6   exclude-result-prefixes="d">
          
      8   <xsl:template match="d:book">
            <xsl:call-template name="id.warning"/>
     10     <div>
              <xsl:apply-templates select="." mode="common.html.attributes"/>
     12       <xsl:if test="$generate.id.attributes != 0">
                <xsl:attribute name="id">
     14           <xsl:call-template name="object.id"/>
                </xsl:attribute>
     16       </xsl:if>
              <xsl:call-template name="book.titlepage"/>
     18       
              <xsl:apply-templates select="d:dedication" 
     20         mode="dedication"/>
              <xsl:apply-templates select="d:acknowledgements"
     22         mode="acknowledgements"/>
              
     24       <xsl:variable name="toc.params">
                <xsl:call-template name="find.path.params">
     26           <xsl:with-param name="table" 
                    select="normalize-space($generate.toc)"/> 
     28         </xsl:call-template>
              </xsl:variable>
     30       
              <xsl:apply-templates/>                               1
     32 
              <xsl:call-template name="make.lots">                 2
     34         <xsl:with-param name="toc.params" select="$toc.params"/>
                <xsl:with-param name="toc">
     36           <xsl:call-template name="division.toc">
                    <xsl:with-param name="toc.title.p"
     38               select="contains($toc.params, 'title')"/>
                  </xsl:call-template>
     40         </xsl:with-param>
              </xsl:call-template>
     42     </div>
          </xsl:template>
     44   
        </xsl:stylesheet>

    1 

    The xsl:apply-templates creates first all the content

    2 

    Create the table of content

  3. Include move-toc.xsl into your customization layer from Step 1:

    <xsl:include href="move-toc.xsl"/>
  4. Build your document with your customization layer.

Discussion

The same principle applies to other structural elements, although the handling is a bit different.


[8]It is not an error to have a parameter with the same name as a named template.

[9]Breadcrumbs are a navigation aid and show the titles from the top page to the current page. The term origins from the trail of breadcrumbs left by Hänsel and Gretel in the popular fairytale written by the Brothers Grimm.

Appendix A. Namensnennung – Keine kommerzielle Nutzung – Weitergabe unter gleichen Bedingungen 3.0 Deutschland

Entnommen von http://creativecommons.org/licenses/by-nc-sa/3.0/de/.

CREATIVE COMMONS IST KEINE RECHTSANWALTSKANZLEI UND LEISTET KEINE RECHTSBERATUNG. DIE BEREITSTELLUNG DIESER LIZENZ FÜHRT ZU KEINEM MANDATSVERHÄLTNIS. CREATIVE COMMONS STELLT DIESE INFORMATIONEN OHNE GEWÄHR ZUR VERFÜGUNG. CREATIVE COMMONS ÜBERNIMMT KEINE GEWÄHRLEISTUNG FÜR DIE GELIEFERTEN INFORMATIONEN UND SCHLIEßT DIE HAFTUNG FÜR SCHÄDEN AUS, DIE SICH AUS DEREN GEBRAUCH ERGEBEN.

Licenz

DER GEGENSTAND DIESER LIZENZ (WIE UNTER “SCHUTZGEGENSTAND” DEFINIERT) WIRD UNTER DEN BEDINGUNGEN DIESER CREATIVE COMMONS PUBLIC LICENSE (“CCPL”, “LIZENZ” ODER “LIZENZVERTRAG”) ZUR VERFÜGUNG GESTELLT. DER SCHUTZGEGENSTAND IST DURCH DAS URHEBERRECHT UND/ODER ANDERE GESETZE GESCHÜTZT. JEDE FORM DER NUTZUNG DES SCHUTZGEGENSTANDES, DIE NICHT AUFGRUND DIESER LIZENZ ODER DURCH GESETZE GESTATTET IST, IST UNZULÄSSIG.

DURCH DIE AUSÜBUNG EINES DURCH DIESE LIZENZ GEWÄHRTEN RECHTS AN DEM SCHUTZGEGENSTAND ERKLÄREN SIE SICH MIT DEN LIZENZBEDINGUNGEN RECHTSVERBINDLICH EINVERSTANDEN. SOWEIT DIESE LIZENZ ALS LIZENZVERTRAG ANZUSEHEN IST, GEWÄHRT IHNEN DER LIZENZGEBER DIE IN DER LIZENZ GENANNTEN RECHTE UNENTGELTLICH UND IM AUSTAUSCH DAFÜR, DASS SIE DAS GEBUNDENSEIN AN DIE LIZENZBEDINGUNGEN AKZEPTIEREN.

  1. Definitionen

    1. Der Begriff “Abwandlung” im Sinne dieser Lizenz bezeichnet das Ergebnis jeglicher Art von Veränderung des Schutzgegenstandes, solange die eigenpersönlichen Züge des Schutzgegenstandes darin nicht verblassen und daran eigene Schutzrechte entstehen. Das kann insbesondere eine Bearbeitung, Umgestaltung, Änderung, Anpassung, Übersetzung oder Heranziehung des Schutzgegenstandes zur Vertonung von Laufbildern sein. Nicht als Abwandlung des Schutzgegenstandes gelten seine Aufnahme in eine Sammlung oder ein Sammelwerk und die freie Benutzung des Schutzgegenstandes.

    2. Der Begriff “Sammelwerk” im Sinne dieser Lizenz meint eine Zusammenstellung von literarischen, künstlerischen oder wissenschaftlichen Inhalten, sofern diese Zusammenstellung aufgrund von Auswahl und Anordnung der darin enthaltenen selbständigen Elemente eine geistige Schöpfung darstellt, unabhängig davon, ob die Elemente systematisch oder methodisch angelegt und dadurch einzeln zugänglich sind oder nicht.

    3. Verbreiten” im Sinne dieser Lizenz bedeutet, den Schutzgegenstand oder Abwandlungen im Original oder in Form von Vervielfältigungsstücken, mithin in körperlich fixierter Form der Öffentlichkeit anzubieten oder in Verkehr zu bringen.

    4. Unter “Lizenzelementen” werden im Sinne dieser Lizenz die folgenden übergeordneten Lizenzcharakteristika verstanden, die vom Lizenzgeber ausgewählt wurden und in der Bezeichnung der Lizenz zum Ausdruck kommen: “Namensnennung”, “Keine kommerzielle Nutzung”, “Weitergabe unter gleichen Bedingungen”.

    5. Der “Lizenzgeber” im Sinne dieser Lizenz ist diejenige natürliche oder juristische Person oder Gruppe, die den Schutzgegenstand unter den Bedingungen dieser Lizenz anbietet und insoweit als Rechteinhaberin auftritt.

    6. Rechteinhaber” im Sinne dieser Lizenz ist der Urheber des Schutzgegenstandes oder jede andere natürliche oder juristische Person oder Gruppe von Personen, die am Schutzgegenstand ein Immaterialgüterrecht erlangt hat, welches die in Abschnitt 3 genannten Handlungen erfasst und bei dem eine Einräumung von Nutzungsrechten oder eine Weiterübertragung an Dritte möglich ist.

    7. Der Begriff “Schutzgegenstand” bezeichnet in dieser Lizenz den literarischen, künstlerischen oder wissenschaftlichen Inhalt, der unter den Bedingungen dieser Lizenz angeboten wird. Das kann insbesondere eine persönliche geistige Schöpfung jeglicher Art, ein Werk der kleinen Münze, ein nachgelassenes Werk oder auch ein Lichtbild oder anderes Objekt eines verwandten Schutzrechts sein, unabhängig von der Art seiner Fixierung und unabhängig davon, auf welche Weise jeweils eine Wahrnehmung erfolgen kann, gleichviel ob in analoger oder digitaler Form. Soweit Datenbanken oder Zusammenstellungen von Daten einen immaterialgüterrechtlichen Schutz eigener Art genießen, unterfallen auch sie dem Begriff "Schutzgegenstand" im Sinne dieser Lizenz.

    8. Mit “Sie” bzw. “Ihnen” ist die natürliche oder juristische Person gemeint, die in dieser Lizenz im Abschnitt 3 genannte Nutzungen des Schutzgegenstandes vornimmt und zuvor in Hinblick auf den Schutzgegenstand nicht gegen Bedingungen dieser Lizenz verstoßen oder aber die ausdrückliche Erlaubnis des Lizenzgebers erhalten hat, die durch diese Lizenz gewährten Nutzungsrechte trotz eines vorherigen Verstoßes auszuüben.

    9. Unter “Öffentlich Zeigen” im Sinne dieser Lizenz sind Veröffentlichungen und Präsentationen des Schutzgegenstandes zu verstehen, die für eine Mehrzahl von Mitgliedern der Öffentlichkeit bestimmt sind und in unkörperlicher Form mittels öffentlicher Wiedergabe in Form von Vortrag, Aufführung, Vorführung, Darbietung, Sendung, Weitersendung, zeit- und ortsunabhängiger Zugänglichmachung oder in körperlicher Form mittels Ausstellung erfolgen, unabhängig von bestimmten Veranstaltungen und unabhängig von den zum Einsatz kommenden Techniken und Verfahren, einschließlich drahtgebundener oder drahtloser Mittel und Einstellen in das Internet.

    10. Vervielfältigen” im Sinne dieser Lizenz bedeutet, mittels beliebiger Verfahren Vervielfältigungsstücke des Schutzgegenstandes herzustellen, insbesondere durch Ton- oder Bildaufzeichnungen, und umfasst auch den Vorgang, erstmals körperliche Fixierungen des Schutzgegenstandes sowie Vervielfältigungsstücke dieser Fixierungen anzufertigen, sowie die Übertragung des Schutzgegenstandes auf einen Bild- oder Tonträger oder auf ein anderes elektronisches Medium, gleichviel ob in digitaler oder analoger Form.

  2. Schranken des Immaterialgüterrechts  Diese Lizenz ist in keiner Weise darauf gerichtet, Befugnisse zur Nutzung des Schutzgegenstandes zu vermindern, zu beschränken oder zu vereiteln, die Ihnen aufgrund der Schranken des Urheberrechts oder anderer Rechtsnormen bereits ohne Weiteres zustehen oder sich aus dem Fehlen eines immaterialgüterrechtlichen Schutzes ergeben.

  3. Einräumung von Nutzungsrechten  Unter den Bedingungen dieser Lizenz räumt Ihnen der Lizenzgeber – unbeschadet unverzichtbarer Rechte und vorbehaltlich des Abschnitts f – das vergütungsfreie, räumlich und zeitlich (für die Dauer des Schutzrechts am Schutzgegenstand) unbeschränkte einfache Recht ein, den Schutzgegenstand auf die folgenden Arten und Weisen zu nutzen (“unentgeltlich eingeräumtes einfaches Nutzungsrecht für jedermann”):

    1. Den Schutzgegenstand in beliebiger Form und Menge zu vervielfältigen, ihn in Sammelwerke zu integrieren und ihn als Teil solcher Sammelwerke zu vervielfältigen;

    2. Abwandlungen des Schutzgegenstandes anzufertigen, einschließlich Übersetzungen unter Nutzung jedweder Medien, sofern deutlich erkennbar gemacht wird, dass es sich um Abwandlungen handelt;

    3. den Schutzgegenstand, allein oder in Sammelwerke aufgenommen, öffentlich zu zeigen und zu verbreiten;

    4. Abwandlungen des Schutzgegenstandes zu veröffentlichen, öffentlich zu zeigen und zu verbreiten.

    Das vorgenannte Nutzungsrecht wird für alle bekannten sowie für alle noch nicht bekannten Nutzungsarten eingeräumt. Es beinhaltet auch das Recht, solche Änderungen am Schutzgegenstand vorzunehmen, die für bestimmte nach dieser Lizenz zulässige Nutzungen technisch erforderlich sind. Alle sonstigen Rechte, die über diesen Abschnitt hinaus nicht ausdrücklich durch den Lizenzgeber eingeräumt werden, bleiben diesem allein vorbehalten. Soweit Datenbanken oder Zusammenstellungen von Daten Schutzgegenstand dieser Lizenz oder Teil dessen sind und einen immaterialgüterrechtlichen Schutz eigener Art genießen, verzichtet der Lizenzgeber auf sämtliche aus diesem Schutz resultierenden Rechte.

  4. Bedingungen  Die Einräumung des Nutzungsrechts gemäß Abschnitt 3 dieser Lizenz erfolgt ausdrücklich nur unter den folgenden Bedingungen:

    1. Sie dürfen den Schutzgegenstand ausschließlich unter den Bedingungen dieser Lizenz verbreiten oder öffentlich zeigen. Sie müssen dabei stets eine Kopie dieser Lizenz oder deren vollständige Internetadresse in Form des Uniform-Resource-Identifier (URI) beifügen. Sie dürfen keine Vertrags- oder Nutzungsbedingungen anbieten oder fordern, die die Bedingungen dieser Lizenz oder die durch diese Lizenz gewährten Rechte beschränken. Sie dürfen den Schutzgegenstand nicht unterlizenzieren. Bei jeder Kopie des Schutzgegenstandes, die Sie verbreiten oder öffentlich zeigen, müssen Sie alle Hinweise unverändert lassen, die auf diese Lizenz und den Haftungsausschluss hinweisen. Wenn Sie den Schutzgegenstand verbreiten oder öffentlich zeigen, dürfen Sie (in Bezug auf den Schutzgegenstand) keine technischen Maßnahmen ergreifen, die den Nutzer des Schutzgegenstandes in der Ausübung der ihm durch diese Lizenz gewährten Rechte behindern können. Dieser Abschnitt a gilt auch für den Fall, dass der Schutzgegenstand einen Bestandteil eines Sammelwerkes bildet, was jedoch nicht bedeutet, dass das Sammelwerk insgesamt dieser Lizenz unterstellt werden muss. Sofern Sie ein Sammelwerk erstellen, müssen Sie auf die Mitteilung eines Lizenzgebers hin aus dem Sammelwerk die in Abschnitt d aufgezählten Hinweise entfernen. Wenn Sie eine Abwandlung vornehmen, müssen Sie auf die Mitteilung eines Lizenzgebers hin von der Abwandlung die in Abschnitt d aufgezählten Hinweise entfernen.

    2. Sie dürfen eine Abwandlung ausschließlich unter den Bedingungen:

      1. dieser Lizenz,

      2. einer späteren Version dieser Lizenz mit denselben Lizenzelementen;

      3. einer rechtsordnungsspezifischen Creative-Commons-Lizenz mit denselben Lizenzelementen ab Version 3.0 aufwärts (z.B. Namensnennung – Keine kommerzielle Nutzung – Weitergabe unter gleichen Bedingungen 3.0 US) oder

      4. der Creative-Commons-Unported-Lizenz mit denselben Lizenzelementen ab Version 3.0 aufwärts

      verbreiten oder öffentlich zeigen (“Verwendbare Lizenz”).

      Sie müssen stets eine Kopie der verwendbaren Lizenz oder deren vollständige Internetadresse in Form des Uniform-Resource-Identifier (URI) beifügen, wenn Sie die Abwandlung verbreiten oder öffentlich zeigen. Sie dürfen keine Vertrags- oder Nutzungsbedingungen anbieten oder fordern, die die Bedingungen der verwendbaren Lizenz oder die durch sie gewährten Rechte beschränken. Bei jeder Abwandlung, die Sie verbreiten oder öffentlich zeigen, müssen Sie alle Hinweise auf die verwendbare Lizenz und den Haftungsausschluss unverändert lassen. Wenn Sie die Abwandlung verbreiten oder öffentlich zeigen, dürfen Sie (in Bezug auf die Abwandlung) keine technischen Maßnahmen ergreifen, die den Nutzer der Abwandlung in der Ausübung der ihm durch die verwendbare Lizenz gewährten Rechte behindern können. Dieser Abschnitt b gilt auch für den Fall, dass die Abwandlung einen Bestandteil eines Sammelwerkes bildet, was jedoch nicht bedeutet, dass das Sammelwerk insgesamt der verwendbaren Lizenz unterstellt werden muss.

    3. Die Rechteeinräumung gemäß Abschnitt 3 gilt nur für Handlungen, die nicht vorrangig auf einen geschäftlichen Vorteil oder eine geldwerte Vergütung gerichtet sind (“nicht-kommerzielle Nutzung”, “Non-commercial-Option”). Wird Ihnen in Zusammenhang mit dem Schutzgegenstand dieser Lizenz ein anderer Schutzgegenstand überlassen, ohne dass eine vertragliche Verpflichtung hierzu besteht (etwa im Wege von File-Sharing), so wird dies nicht als auf geschäftlichen Vorteil oder geldwerte Vergütung gerichtet angesehen, wenn in Verbindung mit dem Austausch der Schutzgegenstände tatsächlich keine Zahlung oder geldwerte Vergütung geleistet wird.

    4. Die Verbreitung und das öffentliche Zeigen des Schutzgegenstandes oder auf ihm aufbauender Abwandlungen oder ihn enthaltender Sammelwerke ist Ihnen nur unter der Bedingung gestattet, dass Sie, vorbehaltlich etwaiger Mitteilungen im Sinne von Abschnitt a, alle dazu gehörenden Rechtevermerke unberührt lassen. Sie sind verpflichtet, die Rechteinhaberschaft in einer der Nutzung entsprechenden, angemessenen Form anzuerkennen, indem Sie – soweit bekannt – Folgendes angeben:

      1. Den Namen (oder das Pseudonym, falls ein solches verwendet wird) des Rechteinhabers und / oder, falls der Lizenzgeber im Rechtevermerk, in den Nutzungsbedingungen oder auf andere angemessene Weise eine Zuschreibung an Dritte vorgenommen hat (z.B. an eine Stiftung, ein Verlagshaus oder eine Zeitung) (“Zuschreibungsempfänger”), Namen bzw. Bezeichnung dieses oder dieser Dritten;

      2. den Titel des Inhaltes;

      3. in einer praktikablen Form den Uniform-Resource-Identifier (URI, z.B. Internetadresse), den der Lizenzgeber zum Schutzgegenstand angegeben hat, es sei denn, dieser URI verweist nicht auf den Rechtevermerk oder die Lizenzinformationen zum Schutzgegenstand;

      4. und im Falle einer Abwandlung des Schutzgegenstandes in Übereinstimmung mit Abschnitt b einen Hinweis darauf, dass es sich um eine Abwandlung handelt.

      Die nach diesem Abschnitt d erforderlichen Angaben können in jeder angemessenen Form gemacht werden; im Falle einer Abwandlung des Schutzgegenstandes oder eines Sammelwerkes müssen diese Angaben das Minimum darstellen und bei gemeinsamer Nennung mehrerer Rechteinhaber dergestalt erfolgen, dass sie zumindest ebenso hervorgehoben sind wie die Hinweise auf die übrigen Rechteinhaber. Die Angaben nach diesem Abschnitt dürfen Sie ausschließlich zur Angabe der Rechteinhaberschaft in der oben bezeichneten Weise verwenden. Durch die Ausübung Ihrer Rechte aus dieser Lizenz dürfen Sie ohne eine vorherige, separat und schriftlich vorliegende Zustimmung des Lizenzgebers und / oder des Zuschreibungsempfängers weder explizit noch implizit irgendeine Verbindung zum Lizenzgeber oder Zuschreibungsempfänger und ebenso wenig eine Unterstützung oder Billigung durch ihn andeuten.

    5. Die oben unter a bis d genannten Einschränkungen gelten nicht für solche Teile des Schutzgegenstandes, die allein deshalb unter den Schutzgegenstandsbegriff fallen, weil sie als Datenbanken oder Zusammenstellungen von Daten einen immaterialgüterrechtlichen Schutz eigener Art genießen.

    6. Bezüglich Vergütung für die Nutzung des Schutzgegenstandes gilt Folgendes:

      1. Unverzichtbare gesetzliche Vergütungsansprüche:  Soweit unverzichtbare Vergütungsansprüche im Gegenzug für gesetzliche Lizenzen vorgesehen oder Pauschalabgabensysteme (zum Beispiel für Leermedien) vorhanden sind, behält sich der Lizenzgeber das ausschließliche Recht vor, die entsprechende Vergütung einzuziehen für jede Ausübung eines Rechts aus dieser Lizenz durch Sie.

      2. Vergütung bei Zwangslizenzen:  Sofern Zwangslizenzen außerhalb dieser Lizenz vorgesehen sind und zustande kommen, behält sich der Lizenzgeber das ausschließliche Recht auf Einziehung der entsprechenden Vergütung für den Fall vor, dass Sie eine Nutzung des Schutzgegenstandes für andere als die in Abschnitt c als nicht-kommerziell definierten Zwecke vornehmen, verzichtet für alle übrigen, lizenzgerechten Fälle von Nutzung jedoch auf jegliche Vergütung.

      3. Vergütung in sonstigen Fällen:  Bezüglich lizenzgerechter Nutzung des Schutzgegenstandes durch Sie, die nicht unter die beiden vorherigen Abschnitte i und ii fällt, verzichtet der Lizenzgeber auf jegliche Vergütung, unabhängig davon, ob eine Einziehung der Vergütung durch ihn selbst oder nur durch eine Verwertungsgesellschaft möglich wäre. Der Lizenzgeber behält sich jedoch das ausschließliche Recht auf Einziehung der entsprechenden Vergütung (durch ihn selbst oder eine Verwertungsgesellschaft) für den Fall vor, dass Sie eine Nutzung des Schutzgegenstandes für andere als die in Abschnitt c als nicht-kommerziell definierten Zwecke vornehmen.

    7. Persönlichkeitsrechte bleiben – soweit sie bestehen – von dieser Lizenz unberührt.

  5. Gewährleistung  SOFERN KEINE ANDERS LAUTENDE, SCHRIFTLICHE VEREINBARUNG ZWISCHEN DEM LIZENZGEBER UND IHNEN GESCHLOSSEN WURDE UND SOWEIT MÄNGEL NICHT ARGLISTIG VERSCHWIEGEN WURDEN, BIETET DER LIZENZGEBER DEN SCHUTZGEGENSTAND UND DIE EINRÄUMUNG VON RECHTEN UNTER AUSSCHLUSS JEGLICHER GEWÄHRLEISTUNG AN UND ÜBERNIMMT WEDER AUSDRÜCKLICH NOCH KONKLUDENT GARANTIEN IRGENDEINER ART. DIES UMFASST INSBESONDERE DAS FREISEIN VON SACH- UND RECHTSMÄNGELN, UNABHÄNGIG VON DEREN ERKENNBARKEIT FÜR DEN LIZENZGEBER, DIE VERKEHRSFÄHIGKEIT DES SCHUTZGEGENSTANDES, SEINE VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK SOWIE DIE KORREKTHEIT VON BESCHREIBUNGEN. DIESE GEWÄHRLEISTUNGSBESCHRÄNKUNG GILT NICHT, SOWEIT MÄNGEL ZU SCHÄDEN DER IN ABSCHNITT 6 BEZEICHNETEN ART FÜHREN UND AUF SEITEN DES LIZENZGEBERS DAS JEWEILS GENANNTE VERSCHULDEN BZW. VERTRETENMÜSSEN EBENFALLS VORLIEGT.

  6. Haftungsbeschränkung  DER LIZENZGEBER HAFTET IHNEN GEGENÜBER IN BEZUG AUF SCHÄDEN AUS DER VERLETZUNG DES LEBENS, DES KÖRPERS ODER DER GESUNDHEIT NUR, SOFERN IHM WENIGSTENS FAHRLÄSSIGKEIT VORZUWERFEN IST, FÜR SONSTIGE SCHÄDEN NUR BEI GROBER FAHRLÄSSIGKEIT ODER VORSATZ, UND ÜBERNIMMT DARÜBER HINAUS KEINERLEI FREIWILLIGE HAFTUNG.

  7. Erlöschen  

    1. Diese Lizenz und die durch sie eingeräumten Nutzungsrechte erlöschen mit Wirkung für die Zukunft im Falle eines Verstoßes gegen die Lizenzbedingungen durch Sie, ohne dass es dazu der Kenntnis des Lizenzgebers vom Verstoß oder einer weiteren Handlung einer der Vertragsparteien bedarf. Mit natürlichen oder juristischen Personen, die Abwandlungen des Schutzgegenstandes oder diesen enthaltende Sammelwerke unter den Bedingungen dieser Lizenz von Ihnen erhalten haben, bestehen nachträglich entstandene Lizenzbeziehungen jedoch solange weiter, wie die genannten Personen sich ihrerseits an sämtliche Lizenzbedingungen halten. Darüber hinaus gelten die Ziffern 1, 2, 5, 6, 7 und 8 auch nach einem Erlöschen dieser Lizenz fort.

    2. Vorbehaltlich der oben genannten Bedingungen gilt diese Lizenz unbefristet bis der rechtliche Schutz für den Schutzgegenstand ausläuft. Davon abgesehen behält der Lizenzgeber das Recht, den Schutzgegenstand unter anderen Lizenzbedingungen anzubieten oder die eigene Weitergabe des Schutzgegenstandes jederzeit einzustellen, solange die Ausübung dieses Rechts nicht einer Kündigung oder einem Widerruf dieser Lizenz (oder irgendeiner Weiterlizenzierung, die auf Grundlage dieser Lizenz bereits erfolgt ist bzw. zukünftig noch erfolgen muss) dient und diese Lizenz unter Berücksichtigung der oben zum Erlöschen genannten Bedingungen vollumfänglich wirksam bleibt.

  8. Sonstige Bestimmungen  

    1. Jedes Mal wenn Sie den Schutzgegenstand für sich genommen oder als Teil eines Sammelwerkes verbreiten oder öffentlich zeigen, bietet der Lizenzgeber dem Empfänger eine Lizenz zu den gleichen Bedingungen und im gleichen Umfang an, wie Ihnen in Form dieser Lizenz.

    2. Jedes Mal wenn Sie eine Abwandlung des Schutzgegenstandes verbreiten oder öffentlich zeigen, bietet der Lizenzgeber dem Empfänger eine Lizenz am ursprünglichen Schutzgegenstand zu den gleichen Bedingungen und im gleichen Umfang an, wie Ihnen in Form dieser Lizenz.

    3. Sollte eine Bestimmung dieser Lizenz unwirksam sein, so bleibt davon die Wirksamkeit der Lizenz im Übrigen unberührt.

    4. Keine Bestimmung dieser Lizenz soll als abbedungen und kein Verstoß gegen sie als zulässig gelten, solange die von dem Verzicht oder von dem Verstoß betroffene Seite nicht schriftlich zugestimmt hat.

    5. Diese Lizenz (zusammen mit in ihr ausdrücklich vorgesehenen Erlaubnissen, Mitteilungen und Zustimmungen, soweit diese tatsächlich vorliegen) stellt die vollständige Vereinbarung zwischen dem Lizenzgeber und Ihnen in Bezug auf den Schutzgegenstand dar. Es bestehen keine Abreden, Vereinbarungen oder Erklärungen in Bezug auf den Schutzgegenstand, die in dieser Lizenz nicht genannt sind. Rechtsgeschäftliche Änderungen des Verhältnisses zwischen dem Lizenzgeber und Ihnen sind nur über Modifikationen dieser Lizenz möglich. Der Lizenzgeber ist an etwaige zusätzliche, einseitig durch Sie übermittelte Bestimmungen nicht gebunden. Diese Lizenz kann nur durch schriftliche Vereinbarung zwischen Ihnen und dem Lizenzgeber modifiziert werden. Derlei Modifikationen wirken ausschließlich zwischen dem Lizenzgeber und Ihnen und wirken sich nicht auf die Dritten gemäß Ziffern a und b angeboteten Lizenzen aus.

    6. Sofern zwischen Ihnen und dem Lizenzgeber keine anderweitige Vereinbarung getroffen wurde und soweit Wahlfreiheit besteht, findet auf diesen Lizenzvertrag das Recht der Bundesrepublik Deutschland Anwendung.

Appendix B. Attribution-NonCommercial-ShareAlike 3.0 Unported

Taken from http://creativecommons.org/licenses/by-nc-sa/3.0/de/deed.en.

CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.

License

THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.

  1. Definitions

    1. Adaptation  means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image (“synching”) will be considered an Adaptation for the purpose of this License.

    2. Collection  means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section g below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.

    3. Distribute  means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.

    4. License Elements  means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, Noncommercial, ShareAlike.

    5. Licensor  means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.

    6. Original Author  means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.

    7. Work  means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.

    8. You  means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.

    9. Publicly Perform  means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.

    10. Reproduce  means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.

  2. Fair Dealing Rights.  Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.

  3. License Grant.  Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:

    1. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections;

    2. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked “The original work was translated from English to Spanish,” or a modification could indicate “The original work has been modified.”;

    3. to Distribute and Publicly Perform the Work including as incorporated in Collections; and,

    4. to Distribute and Publicly Perform Adaptations.

    The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section f, all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights described in Section e.

  4. Restrictions.  The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:

    1. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section a applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section d, as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section d, as requested.

    2. You may Distribute or Publicly Perform an Adaptation only under: (i) the terms of this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-NonCommercial-ShareAlike 3.0 US) (“Applicable License”). You must include a copy of, or the URI, for Applicable License with every copy of each Adaptation You Distribute or Publicly Perform. You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License. You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section b applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License.

    3. You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in con-nection with the exchange of copyrighted works.

    4. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section a, keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution (“Attribution Parties”) in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section b, in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., “French translation of the Work by Original Author,” or “Screenplay based on original Work by Original Author”). The credit required by this Section d may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.

    5. For the avoidance of doubt:

      1. Non-waivable Compulsory License Schemes.  In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;

      2. Waivable Compulsory License Schemes.  In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section c and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and,

      3. Voluntary License Schemes.  The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section c.

    6. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section b of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section b of this License (right to make Adaptations) but not otherwise.

  5. Representations, Warranties and Disclaimer  UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING AND TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THIS EXCLUSION MAY NOT APPLY TO YOU.

  6. Limitation on Liability.  EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

  7. Termination  

    1. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.

    2. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.

  8. Miscellaneous  

    1. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.

    2. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.

    3. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

    4. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.

    5. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.

    6. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.