DocBook CookBook
Updated
19 Mar 2008
    Linking
    DocBook XSL
    Printing
      +Inline Titles <-

Rendering a Section Title Inline

Problem

You need a “inline” section title; that is, a title that is on the same line as the section it introduces. For example,

Example 1. Inline Section Title


  Section Title  Content of the section ....
        


The standard DocBook fo stylesheets put the section title on a separate line, in a separate <fo:block>, then process the content that follows in its own <fo:block> in a completely different part of the stylesheets.

This gives you something like the following:

Example 2. Normal Section Title


  Section Title

    Content of the section ....
        


Because the processing of the title and the content that follows are handled in different parts of the XSL stylesheets, there's no parameter or other easy way to get an inline title.

Solution

This solution assumes you want inline titles to start at a particular section level and continue for lower level headings. It also assumes that the element that immediately follows the title is a <para>.

This customization modifies the section.heading template to check the heading level, and if it is at or below the level for inline headings, call a new template, inline.section.heading. If the heading level is above the level for inline headings, the rest of the section.heading template is executed as usual. The inline.section heading template processes the title and the following <para> together, instead of letting the paragraph be processed normally. Finally, two empty templates are included to suppress the normal paragraph processing, since this has already been handled in the inline.section.heading template.

Here is a sample customization using the namespaced version of DocBook XSL, Version 1.73.2:

Example 3. Run-in title customization

<xsl:stylesheet
  xmlns:d="http://docbook.org/ns/docbook"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fo="http://www.w3.org/1999/XSL/Format"
  version="1.0">

  <!-- adjust as needed to point to the standard stylesheets -->
  <xsl:import
   href="http://docbook.sourceforge.net/release/xsl-ns/current/fo/docbook.xsl"/>

  <!-- spacing for paragraph after inline title;
       same set of attributes as normal.para.spacing -->
  <xsl:attribute-set name="inline.para.spacing">
    <!-- set as appropriate -->
  </xsl:attribute-set>

  <!-- titles at this level and lower will be inline -->
  <xsl:param name="inline.header.level">3</xsl:param>

  <!-- Turns off normal para processing when titles are inline.
       inline.section.heading already handles this. 
       CAVEAT:  These two templates are hard-coded for third
                level headings -->

  <xsl:template
       match="d:section/d:section/d:section/d:para[preceding-sibling::*[1][self::d:title]]"/>

  <xsl:template
       match="d:sect3/d:para[preceding-sibling::*[1][self::d:title]]"/>

  <!-- Processes the first para after an inline title -->
  <xsl:template match="d:para" mode="inline.para">
    <fo:inline xsl:use-attribute-sets="normal.para.spacing">
      <xsl:call-template name="anchor"/>
      <xsl:apply-templates/>
    </fo:inline>
  </xsl:template>


  <!-- Modify section heading to call inline.section.heading when
       heading level is above $inline.header.level -->
  <xsl:template name="section.heading">
    <xsl:param name="level" select="1"/>
    <xsl:param name="marker" select="1"/>
    <xsl:param name="title"/>
    <xsl:param name="marker.title"/>

    <xsl:choose>
      <xsl:when test="$level >= $inline.header.level">
        <fo:block xsl:use-attribute-sets="inline.para.spacing">
          <xsl:call-template name="inline.section.heading">
            <xsl:with-param name="level" select="$level"/>
            <xsl:with-param name="title" select="$title"/>
            <xsl:with-param name="marker" select="$marker"/>
            <xsl:with-param name="marker.title" select="$marker.title"/>
          </xsl:call-template>
          <xsl:apply-templates select="following-sibling::*[1]"
                               mode="inline.para"/>
        </fo:block>
      </xsl:when>
      <xsl:otherwise>
      <!-- copy unchanged all of contents of the section.heading template.
           Using xsl 2.0, you could use xsl:apply-imports
           with parameters; xsl 1.0 won't let you do that.  -->
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- this templates is identical to section.heading,
       except all instances of fo:block have been replaced
       with fo:inline. -->
  <xsl:template name="inline.section.heading">
    <xsl:param name="level" select="1"/>
    <xsl:param name="marker" select="1"/>
    <xsl:param name="title"/>
    <xsl:param name="marker.title"/>

    <fo:inline xsl:use-attribute-sets="section.title.properties">
      <xsl:if test="$marker != 0">
        <fo:marker marker-class-name="section.head.marker">
          <xsl:copy-of select="$marker.title"/>
        </fo:marker>
      </xsl:if>

      <xsl:choose>
        <xsl:when test="$level=1">
          <fo:inline xsl:use-attribute-sets="section.title.level1.properties">
            <xsl:copy-of select="$title"/>
          </fo:inline>
        </xsl:when>
        <xsl:when test="$level=2">
          <fo:inline xsl:use-attribute-sets="section.title.level2.properties">
            <xsl:copy-of select="$title"/>
          </fo:inline>
        </xsl:when>
        <xsl:when test="$level=3">
          <fo:inline xsl:use-attribute-sets="section.title.level3.properties">
            <xsl:copy-of select="$title"/>
          </fo:inline>
        </xsl:when>
        <xsl:when test="$level=4">
          <fo:inline xsl:use-attribute-sets="section.title.level4.properties">
            <xsl:copy-of select="$title"/>
          </fo:inline>
        </xsl:when>
        <xsl:when test="$level=5">
          <fo:inline xsl:use-attribute-sets="section.title.level5.properties">
            <xsl:copy-of select="$title"/>
          </fo:inline>
        </xsl:when>
        <xsl:otherwise>
          <fo:inline xsl:use-attribute-sets="section.title.level6.properties">
            <xsl:copy-of select="$title"/>
          </fo:inline>
        </xsl:otherwise>
      </xsl:choose>
    </fo:inline>
  </xsl:template>


</xsl:stylesheet>

      
      

Discussion

The main complication is that you need to process the following <para> element along with the title to keep each of them from being wrapped in <fo:block> elements and therfore separated.

References