Customizing the DITA OpenToolkit

This paper outlines a course given by Adena Frazier of Suite Solutions--a course which is highly recommended for anyone who wants to get the most of the OT. This paper outlines the most important processes, but it leaves out many of the details, tips, and debugging notes that were included in the course. Note, too, that errors easily could have crept in, and some details are bound to change for later versions of the toolkit. (We used version 1.4.1) So it makes a  lot of sense to take the course, even if you find the outline useful.

High-level Synopsis

Day One covered some basics like DTDs, installing and running the DITA Open Toolkit, ANT build files, and .ditaval files. But it was mostly devoted to the XPath mechanisms for addressing and selecting nodes (the crux of XSL transforms) and the XSL-FO format (the crux of PDF generation).

Day Two focused on customizing PDF. Day Three listed the advantages and disadvantages of the different varieties of xHTML, and then focused on customizing xHTML.

Day Three also included a review of publishing alternatives, including XPP, RoboHelp, WebWorks, and DITA_FMx, but didn't go into detail on any of them.

PDF(2) Path

To customize PDF(2) output:

  1. a) Make a directory that models the existing one:
    demo/
      fo/
        customization/
        yourCustomization/
    <-- create in this location
     
  2. Copy XSLT files you want to customize (preserving directory structure) and make changes to the XSLT in it.

    You generally copy the whole file, because if change point size for one heading, there are probably a raft of dependent changes you'll want to make. With the whole file to look at, it's easy to find things and make changes.

    The directory structure is really weird, with attribute customization files far removed from element customization files:
    yourCustomization/fo/
       attr/custom.xsl -- attributes
          ...(many dirs)...
       xsl/custom.xsl -- elements

  3. Point to that directory using the argument customization.dir in the (ANT or command line) production script
     
  4. Fix in a bug in the "reflection" scripts that affect titles and list elements. Those elements generate the style to apply based on the depth of the element. But in doing so, they hard code a path to the original templates, which prevents customizations from taking effect.

    To make that fix:
    1. Copy demo/fo/xsl/common-attr-set-reflection.xsl
    2. Look for occurrences of "../../cfg/"
    3. Modify the path so it goes to your customizationdirectory from the demo/fo/xsl directory.
       
  5. Adjust one other configuration file to make the customizations take effect.
    (Copy catalog.xml.orig to catalog.xml and uncomment the line that corresponds to the XSL you've overridden.)

XPP Path to PDF

XHTML Path

The explanation here represents my best understanding, to date. It may well be revised when I 've had a chance to play with it more.

To customize xHTML output, use the instructions below. Hopefully, this picture will help to clarify the relationships between the files (click for a larger version):

xhtml customization file relationships

Here's the process:

  1. Read this file to find out which XSL files are included, and to get the ID of the extension:
    xsl/ditaxhtml_template.xsl

    The extension point is defined by this line:
    <dita:extension id="dita.xsl.xhtml" ...

    (Templates are copied by the integrator in the last stage of the process. During the copy, your extensions are substituted, using element IDs as a guide.)

  2. Most all of the templates you would want to extend are in:
    xsl/xslhtml/dita2htmlImpl.xsl

    Look for "STUBS FOR USER PROVIDED OVERRIDE EXTENSIONS"
    Pick the thing you want under that. For example:

    <xsl:template name="gen-user-header">
      <!-- to customize: copy this to your override transform
           and add the content you want. -->
      <!-- it will be placed in the running heading section of the XHTML. -->
    </xsl:template>

    Note that the instructional comments seem to be slightly misleading here. In reality, you add a "match" phrase and change the "name" attribute to "mode" That was true for the example we had in class, at least. Here's what we had:

    <xsl:template match="/|node()|@*" mode="gen-user-header">
      <div>...title and other stuff here...</div>
    </xsl:template>

    (The match expression says "root or element node or attribute". It's just a given, mandated by the fact that this file is being used to insert the <div>...</div> content into a copy of dita2xhtml_template when the integration transform runs.)

    Overloaded Terminology Note:
    _template.xsl and <xsl:template> both use the word "template", but in two different ways.

    Note:
    Many transform templates contain matches like this:
      match="*[contains(@class,' topic/abstract ')...

    That pattern looks for an item in the class attribute, rather than matching an element name. A specialized element will have multiple entries that names its parent as well as itself: class="topic/topic myTopic/myTopic" Transforms that operate on the generic topic class will therefore work, unless a specific "myTopic" transform has been defined.

  3. Put the template extensions into a new file:
      demo/
        yourCustomization/
          xsl/
            yourTransform.xsl <-- create

    where the file looks like this:

  4. <xsl:stylesheet version="1.0"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
       ...template(s) here...
    
    </xsl:stylesheet>

    Note:
    You typically only put the transforms you're changing into the file, to keep things simple. (CSS takes care of point sizes, so you don't need to copy the whole file, the way you do in PDF.)

  5. Create the plugin.xml file that identifies your extensions so they can be integrated into the toolkit:
      demo/
        yourCustomization/
          plugin.xml <-- create
          xsl/
            yourTransform.xsl
            ...
     
  6. Point to the extension file(s) from the plugin file:
    <?xml version="1.0" encoding="UTF-8"?>
    <plugin id="YourCompany.branding">     <--for example
       <feature extension="dita.xsl.html"  <--from step (a)
          value="xsl/yourTransform.xsl"    <--from step (c)
          type="file"
        />
    /plugin>
  7. Run the OT integrator build process from the top directory:
      ant integrator.xml

    This step copies the xyz_template.xsl files, creating the xyz.xsl files and substituting your extensions.

    Note:
    The fo/ plugin also has an integrator process. But that's not the one you want.