Edit online

Creating a simple DITA Open Toolkit plugin to customize published HTML and PDF content

24 Dec 2013
Read time: 7 minute(s)

I recently worked on a DITA Open Toolkit plugin which can be used to provide syntax highlight when publishing DITA codeblock elements to HTML-based or PDF outputs.

Based on this experience I've put together some steps to help anyone wanting to create an XSLT customization plugin for the DITA Open Toolkit for HTML and PDF based outputs.
  1. Create a folder for your plugin in the DITA OT plugins folder. The DITA OT bundled with Oxygen can be found here: OXYGEN_INSTALL_DIR/frameworks/dita/DITA-OT. In my case I created the following folder: OXYGEN_INSTALL_DIR/frameworks/dita/DITA-OT/plugins/com.oxygenxml.highlight.
  2. Create a plugin.xml file in that folder containing the plugin's extension points. In my case, the plugin descriptor file contains:
    <plugin id="com.oxygenxml.highlight">
      <feature extension="package.support.name" value="Oxygen XML Editor Support"/>
      <feature extension="package.support.email" value="support@oxygenxml.com"/>
      <feature extension="package.version" value="1.0.0"/>
      <feature extension="dita.xsl.xhtml" value="xhtmlHighlight.xsl" type="file"/>
      <feature extension="dita.xsl.xslfo" value="pdfHighlight.xsl" type="file"/>
    </plugin>
    The important extensions in it are the references to the XSLT stylesheets which will be used to style the HTML and the PDF outputs. You can find a bunch of other DITA OT plugin extension points here:https://www.dita-ot.org/dev/extension-points/plugin-extension-points.html.
  3. Create an XSLT stylesheet called xhtmlHighlight.xsl located in the same plugin folder. As I want to overwrite the creation of the HTML content from a DITA codeblock element I will first need to find the XSLT template that I need to overwrite. A DITA codeblock element has the class attribute value "+ topic/pre pr-d/codeblock ". Usually in such cases I take part of the class attribute value and search using the "Find/Replace in Files" Oxygen action in all of the DITA OT XSLT resources. In this case I searched for topic/preand found this XSLT stylesheet:OXYGEN_INSTALL_DIR/frameworks/dita/DITA-OT/plugins/org.dita.xhtml/xsl/xslhtml/dita2htmlImpl.xsl containing this XSLT template:
    <xsl:template match="*[contains(@class, ' topic/pre ')]" name="topic.pre">
      <xsl:if test="contains(@frame, 'top')"><hr /></xsl:if>
      <xsl:apply-templates select="*[contains(@class, ' ditaot-d/ditaval-startprop ')]" mode="out-of-line"/>
      <xsl:call-template name="spec-title-nospace"/>
      <pre>
        <xsl:attribute name="class" select="name()"/>
        <xsl:call-template name="commonattributes"/>
        <xsl:call-template name="setscale"/>
        <xsl:call-template name="setidaname"/>
        <xsl:apply-templates/>
      </pre>
      <xsl:apply-templates select="*[contains(@class, ' ditaot-d/ditaval-endprop ')]" mode="out-of-line"/>
      <xsl:if test="contains(@frame, 'bot')"><hr /></xsl:if><xsl:value-of select="$newline"/>
    </xsl:template>
    thus my xhtmlHighlight.xsl will overwrite the content of the template like:
    <xsl:template match="*[contains(@class, ' topic/pre ')]" name="topic.pre">
      <xsl:if test="contains(@frame, 'top')"><hr /></xsl:if>
      <xsl:apply-templates select="*[contains(@class, ' ditaot-d/ditaval-startprop ')]" mode="out-of-line"/>
      <xsl:call-template name="spec-title-nospace"/>
      <pre>
        <xsl:attribute name="class" select="name()"/>
        <xsl:call-template name="commonattributes"/>
        <xsl:call-template name="setscale"/>
        <xsl:call-template name="setidaname"/>
         <!--Here I'm calling the styler of the content inside the codeblock.-->
         <xsl:call-template name="outputStyling"/>
      </pre>
      <xsl:apply-templates select="*[contains(@class, ' ditaot-d/ditaval-endprop ')]" mode="out-of-line"/>
      <xsl:if test="contains(@frame, 'bot')"><hr /></xsl:if><xsl:value-of select="$newline"/>
    </xsl:template>
    and call another XSLT template which applies as a Java extension the XSLTHL library to style the content.
  4. Create an XSLT stylesheet called pdfHighlight.xsl located in the same plugin folder which will contain the PDF XSLT customization. In this case I will overwrite the XSLT template from:OXYGEN_INSTALL_DIR/frameworks/dita/DITA-OT/plugins/org.dita.pdf2/xsl/fo/topic.xsl which has the content:
        <xsl:template match="*[contains(@class,' topic/pre ')]">
            <xsl:call-template name="setSpecTitle"/>
            <fo:block xsl:use-attribute-sets="pre">
                <xsl:call-template name="commonattributes"/>
                <xsl:call-template name="setFrame"/>
                <xsl:call-template name="setScale"/>
                <xsl:call-template name="setExpanse"/>
                <xsl:apply-templates/>
            </fo:block>
        </xsl:template>
  5. In order to install your plugin in the DITA OT you need to run the integrator. In the Oxygen Transformation Scenarios view there is a Show all scenarios action available in the drop down settings button. Just check that and execute the transformation scenario called Run DITA OT Integrator. And that's it, your XSLT content will be applied with priority when publishing both to XHTML-based and to PDF-based outputs.

    Let's take now a look at what that misterious step (5) - running the integrator to install the plugin - really did:
    • In the XSLT stylesheet:OXYGEN_INSTALL_DIR/frameworks/dita/DITA-OT/plugins/org.dita.xhtml/xsl/dita2html-base.xsl a new import automatically appeared:
      <xsl:import href="plugin:com.oxygenxml.highlight:xhtmlHighlight.xsl"/>
      This import is placed after all base imports and because of this it has a higher priority. More about imported template precedence can be found in the XSLT specs:http://www.w3.org/TR/xslt#import.
    • Likewise, in the top-level stylesheets related to PDF publishing like:OXYGEN_INSTALL_DIR/frameworks/dita/DITA-OT/plugins/org.dita.pdf2/xsl/fo/topic2fo_shell.xsl a new import statement has appeared:
      <xsl:import href="plugin:com.oxygenxml.highlight:pdfHighlight.xsl"/>
    Now you can take your plugin's folder and distribute it to anyone having a DITA OT installation along with some simple installation notes. Your customization will work as long as the templates you are overwriting have not changed from one DITA OT distribution to the other.

    This video from the DITA OT Day 2018 in Rotterdam has also steps for implementing a simple DITA OT plugin: https://www.oxygenxml.com/events/2018/dita-ot_day.html#step_by_step_implementation_of_a_DITA.