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 

Wednesday, November 27, 2013

Generating and using IDs for DITA elements

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr

Generating and using IDs for DITA elements

Generating IDs in DITA

ID values can be generated either on request or automatically for DITA elements. 

Generate ID values on two paragraphs
Generate ID values on two paragraphs using the contextual menu
The action that you can invoke to generate IDs is called Generate IDs and you can access this from the contextual menu or from the DITA main menu. The action acts on the current selection or, if there is no selection, on the current element. The format of the ID value as well as the elements on which ID values are generated automatically can be customized from the DITA->ID Options menu.
DITA ID Options menu
DITA -> ID Options menu
The default settings will configure oXygen to generate automatically IDs for topics, tables, figures and lists and the ID value will start with the element local name followed by some unique string.
The elements for which ID values will be generated automatically are specified using class attribute values, that means the automatic ID generation is specialization-aware, it will work not only for the elements defined as part of the DITA standard, but also for any custom specialization that defines its own specialized topics, tables, figures or lists.
The ID Options dialog
The pattern for the ID values can be customized using constant strings and editor variables. The common editor variables that are used for these values are ${lcoalName}, ${id} and ${uuid}, please refer to the user guide for more information on editor variables.
The ID value of an element can be manually added, removed or modified using the Attributes panel to access the id attribute of that element.
This action to generate ID values for DITA is part of the DITA framework configuration, so you can easily remove it or configure a different custom action to generate IDs. But in general, you should not need to change the ID generation because specific ID values should not matter that much.

Using IDs in DITA

Elements that have an ID value defined for their id attribute can be referred by that ID value from other parts of the DITA topic or from other topics, in order to create links or to reuse those elements. oXygen provides DITA specific actions to create DITA links and content references as part of the DITA framework. These default actions feature search and filter capabilities that should help you identify the element to point to, without the need to put semantic information in the ID value itself.

Here it is an example of adding a content reference to a topic. Let's say we have this topic talking about inserting the SIM card in a phone. For that we need to remove the battery, insert the SIM and then add the battery. If we already have a task for removing the battery then we can reuse those steps instead of duplicating them. At the beginning of the steps element we need to add a content reference to refer to the steps from the task that describes how to remove the battery.
A task that describes how to insert a SIM in a telephone
We position the caret inside the steps element, before the first step and invoke the Insert a DITA content reference action. This will show the Insert Content Reference dialog.
The insert content reference dialog


Now, let's suppose we do not remember the task file name that talked about removing the battery, what can we do? We can use the drop-down from the action next to the URL field and choose Search for file.
Trigger the Find Resource dialog


Now oXygen will show the Find Resource dialog where you can search for content to identify the task that describes how to remove the battery. For example, once you start typing in the search field "rem", oXygen will show you the topics that match this prefix, sorted by relevance.
The Find Resource dialog showing topics that match the search criteria

The first match seems to be the one we want, if we look at the title, so we select it. oXygen will load that topic in the Insert Content Reference dialog and it will present all the defined IDs, showing a preview of each entry you select.
Insert content reference displaying the available IDs in a topic


 Now, you can filter on the type of element that you want to refer using the Target Type combobox and you can also filter on content, topic ID and element ID using the Filter input. As the content is dynamically gathered from each element, it is a better practice to use this search functionality than to put part of the content in the ID value. If the content changes in time that ID value will be very difficult to maintain to keep it up-to-date with the changes made to content - either you leave an old ID value that does not match the updated content, or you change the ID value and then you need to change all the references to that ID.
We can filter for example to see only the task steps that contain "remove"
Filtered IDs

We see now the entry that we want, we preview it and choose to make a conref to this step.
The topic contains a content reference to the identified step

This functionality works similarly for links and helps you search on the content itself and not on the ID value to refer to an element.
The search functionality is available also directly in oXygen, both as a dialog and as a side view, for example if you use Window->Show View->Open/Find Resource then you will see the Open/Find Resource view that will help you search through all your resources, in content, in file paths and in reviews. The content search also supports XML elements, for example "title:battery" will find all topics that have the word battery in their title.
The find resources view
 
You can then open the topic you found, maybe generate IDs for elements that you want to reuse and then you can also drag and drop or copy and paste as link or paste as content reference to quickly link or reuse that content.


Some conclusions

You can use oXygen to automatically add ID values the elements that you usually reuse in your DITA topics or you can generate ID values on request, for specific elements. You can customize to some degree the ID format but that should not be very important, because if you want to store semantic information inside the ID value, like adding some of the content of the element, then maintenance will became a nightmare. Instead, you should take advantage of the search and filtering support that oXygen provides to search for the actual content of the element you want to link to.


Friday, November 22, 2013

The Oxygen SDK (Part 1: Plugins)

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr
During the last years we added a lot of API and extension points to Oxygen in order to allow for different customizations to the application.

But our documentation is sometimes lacking. We mostly rely on Javadoc documentation and on Java samples.

Here's some feedback we got at the last Oxygen Users Meetup in Munich this year:
Too less information about frameworks, plugins, everything is spread over certain documents, webinars, etc . Please centralize these information in one form.
I will try to centralize these resources and add some useful links for people who want to start customizing Oxygen.

First the difference between a framework and a plugin:
  • A plugin can be used to customize the behavior of the entire application no matter what XML document is currently being edited.
  • A framework configuration provides validation, content completion and editing support for a specific XML vocabulary.

 

Plugins:

A plugin is a folder containing a descriptor plugin.xml file and various other JAR libraries and resources.

http://www.oxygenxml.com/doc/ug-oxygen/index.html#topics/preferences-plugins.html

Only the standalone version of Oxygen supports plugins.
The Eclipse Plugin version of Oxygen is itself a plugin and can be customized by adding a plugin in the Eclipse workbench which depends on the Oxygen Eclipse plugin.
Despite of this, most of the API is common.

The plugin can be deployed either by copying it to the plugins folder of an Oxygen installation:

http://www.oxygenxml.com/doc/ug-oxygen/tasks/howto-install-plugin.html

 or by deploying it as an add-on:

http://www.oxygenxml.com/doc/ug-oxygen/index.html#tasks/deploying-addons.html

The Oxygen Plugins SDK:

http://www.oxygenxml.com/oxygen_sdk.html#Developer_Plugins

contains Java sources and Javadoc for all the API accessible from a plugin.

The Plugins SDK also contains sample plugins and their Java code. This Java code should be very helpful to get you started and to show how various API can be used.

Although there are many types of plugins:

http://www.oxygenxml.com/doc/ug-oxygen/index.html#topics/pluginTypes.html

the most useful plugin extension type is the "Workspace Access" extension type:

http://www.oxygenxml.com/doc/ug-oxygen/index.html#concepts/workspace-access-plugin.html

This kind of plugin allows you to use the API and add or remove toolbar and main menu buttons, add custom views and toolbars. It also allows you to access and control/make changes to the XML documents opened in the workbench.

As an example, all full-featured integrations which have been created to connect Oxygen with a specific CMS or remote repository use a combination of "Workspace Access" and "Custom Protocol" plugin:

http://www.oxygenxml.com/doc/ug-oxygen/index.html#topics/howto-cms-plugin.html

You can create automated tests for your plugins:

http://www.oxygenxml.com/doc/ug-oxygen/index.html#topics/automated-tests.html

and even debug their functionality:

http://www.oxygenxml.com/doc/ug-oxygen/index.html?q=/doc/ug-oxygen/topics/debug-plugin.html

Thursday, October 31, 2013

Using MathJax to properly view MathML equations in the WebHelp output.

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr
MathJax is a solution to properly view MathML equations embedded in HTML content in a variety of browsers:


http://www.mathjax.org/

Let's say you have Docbook or DITA content which has embedded MathML equations and you want to properly view the equations in the published WebHelp output.
Without  the help of the MathJax Javascript code, right now only Firefox can render the equations.

For my tests I created a new DITA topic starting from our "DITA Composite with MathML" new file template which contains an embedded MathML equation. Then I referenced this topic in a small DITA Map.

The PDF output created using Apache FOP properly displayed the MathML equation so you do not need any customization for it.

As for the HTML output in order to use MathJax I created a file called footer.html with the content:

<script type="text/javascript"
    src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

Then I edited the DITA Map WebHelp transformation scenario and set the parameter args.hdf to point to the footer.html resource.

I transformed to WebHelp and the equation was properly rendered in the browsers I tested with (IE, Chrome and Firefox).


Tuesday, October 08, 2013

oXygen XML Editor 15.1 is available!

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr
We are pleased to announce the release of oXygen XML Editor version 15.1. 


With the release of version 15.1, oXygen is the first XML editor to fully support right-to-left and bidirectional text in the visual editing mode. Content authors are now able to create and edit XML documents in the oXygen Author mode, in languages like Arabic, Hebrew, Persian and others.
This version of oXygen makes a leap forward in working with XML modules. Using the Master Files support, oXygen assists you while editing an XML document that belongs to a set of assembled modules, and provides you features like module validation, in-context content completion assistant, ID referencing or module connection overview.
The integration of the entire DITA for Publishers plugins suite enables oXygen users to produce Kindle output from DITA maps.
The latest Eclipse version (4.3) is now supported by the oXygen Eclipse plugin. Also, to keep you up-to-date, we bundled the latest third party components like Saxon Enterprise Edition 9.5.1.2, TEI Schemas (2.5.0), TEI Stylesheets (7.1.0), DITA for Publishers 0.9.18, and Calabash 1.0.13.

Click here to find out more about what's new this new version.

Friday, February 15, 2013

oXygen XML Editor version 14.2 has arrived!

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr
Version 14.2 of <oXygen/> XML Editor adds important features for both XML Development and XML Authoring.
On the XML development side, <oXygen/> completes the set of XML Schema 1.1 related features with full schema editing support and capabilities to generate XML instances and schema documentation in accordance with this new W3C standard.
On the XML Authoring side, <oXygen/> streamlines XML reviewing by adding support for highlights and a Review manager panel. Highlights help you focus on the content you need to review and the Review manager panel presents all the changes, comments and highlights from a document so you can quickly inspect and manage them.

The latest version additions are described at: http://www.oxygenxml.com/#new-version