Tuesday, December 24, 2013

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

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr
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. The plugin will be available in Oxygen 15.2 at the beginning of 2014.

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:

http://dita-ot.sourceforge.net/1.5.3/dev_ref/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/pre and found this XSLT stylesheet:

OXYGEN_INSTALL_DIR/frameworks/dita/DITA-OT/xsl/xslhtml/dita2htmlImpl.xsl 

containing this XSLT template:

<xsl:template match="*[contains(@class,' topic/pre ')]" name="topic.pre">
  <xsl:apply-templates select="."  mode="pre-fmt" />
</xsl:template>
 
thus my xhtmlHighlight.xsl will overwrite the content of the template like:

<xsl:template match="*[contains(@class,' topic/pre ')]" name="topic.pre">
    <!-- This template is deprecated in DITA-OT 1.7. Processing will moved into the main element rule. -->
    <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"><xsl:value-of select="name()"/></xsl:attribute>
      <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/legacypdf/xslfo/dita2fo-elems.xsl

which has the content:

<xsl:template match="*[contains(@class,' topic/pre ')]">
  <xsl:call-template name="gen-att-label"/>
  <fo:block xsl:use-attribute-sets="pre">
    <!-- setclass -->
    <!-- set id -->
    <xsl:call-template name="setscale"/>
    <xsl:call-template name="setframe"/>
    <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 (WebHelp, CHM, EPUB, JavaHelp, Eclipse Help) 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:

a) In the XSLT stylesheet:

OXYGEN_INSTALL_DIR/frameworks/dita/DITA-OT/xsl/dita2html-base.xsl

a new import automatically appeared:

<xsl:import href="../plugins/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

b) 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_fop.xsl

a new import statement has appeared:

<xsl:import href="../../../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.

Thursday, December 19, 2013

Collaboration (Teams working on a common XML project)

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr
Sometimes I get the feeling that there are still many users who collaborate on XML projects using shared network drives.

We got this question  yesterday from one of our users:
I am just curious if housing and working off a network drive is possible, and if so, what are the risks involved?
In my opinion having multiple writers edit documents from a common shared network location is dangerous because you may end up overwriting the content that someone else has been writing on.

You also have no history of who made what modification and no redundancy of content. If somehow the network drive fails because of a hardware problem or files get corrupted you have no copy of your repository to start over.

My advice is to start using a free and open source version system like Subversion (SVN), CVS or GIT.
For example Oxygen comes with an embedded SVN Client and for writing our user manual which is DITA-based we collaborate using a subversion server installed on a Linux machine.
We made a small video demonstration showing how this colaboration is done:

http://www.oxygenxml.com/demo/Collaborative_Authoring_Using_Subversion.html

The advantage to using version systems is immense:
  1. We know the history of each resource.
  2. We know who made what change.
  3. We can create tags and branches for marking certain versions of the documentation.
  4. Each user has his own local copy of the repository and if the server fails we have the same content duplicated in many other places.
Other approaches:

Use a WebDav repository. When Oxygen opens an XML document from a WebDav repository, it locks the XML document and thus prevents other users from saving changes to it while still allowing them to open the document.

Use a Commercial CMS which in addition to an open source version system will bring more workflow related tools and lots of ways to keep your content valid. And there are quite a few CMSs which have an integration with Oxygen:

http://www.oxygenxml.com/partners.html#solutionpartners%28cms%29

Here's a very nice post by Eliot Kimber about implementing DITA without a CSM:

http://drmacros-xml-rants.blogspot.com#4627052924135934849