Thursday, October 13, 2016

Replacing direct image references with key references in a DITA Project

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr
Let's say that you have a large DITA project and all the image references in your topics are direct, using the @href attribute like this:
<image href="../../images/Iris_sanguinea.jpg" scale="50"/>
and for better scalability and reuse you want to convert these direct references to DITA 1.2 key references:
<image keyref="Iris_sanguinea.jpg" scale="50"/>

Doing something like this manually means making replacements in hundreds of places and in addition manually building a DITA Map which maps the image file name to the image location.

This blog post will try to describe some steps that you can take in order to automate this change in your project:
  1. The first big step is the generation of the DITA Map which maps each image file name (which will be used as a key) to the image location. So the generated DITA Map will look like this:
    <!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
    <keydef href="Iris_sanguinea.jpg" keys="Iris_sanguinea.jpg"/>
    We will assume that all images are placed in an images folder and we can create an ANT build file which lists all the images in a parameter and then calls an XSLT script to process the list of images further:
    <project basedir="." name="Create Image Keys Definition Map">
        <fileset id="dist.contents" dir="images/" includes="*"/>
        <property name="prop.dist.contents" refid="dist.contents"/>
        <xslt in="createKeyrefsMap.xsl" style="createKeyrefsMap.xsl" out="images/imageKeydefs.ditamap" destdir=".">
            <param name="filesList" expression="${prop.dist.contents}"/>
    The XSLT stylesheet createKeyrefsMap.xsl is responsible for creating the mapping DITA Map:
    <xsl:stylesheet xmlns:xsl=""
        <xsl:param name="filesList"/>
        <xsl:output doctype-public="-//OASIS//DTD DITA Map//EN" doctype-system="map.dtd" indent="yes"/>
        <xsl:template match="/">
                <xsl:call-template name="tokenizeString">
                    <xsl:with-param name="list" select="$filesList"/>
        <xsl:template name="tokenizeString">
            <xsl:param name="list"/>
            <xsl:param name="delimiter" select="';'"/>
                <xsl:when test="contains($list, $delimiter)">
                    <keydef href="{substring-before($list,$delimiter)}" keys="{substring-before($list,$delimiter)}"/>
                    <xsl:call-template name="tokenizeString">
                        <xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
                    <keydef href="{$list}" keys="{$list}"/>

    So after this step you will have a new DITA Map with all image mappings, DITA Map which you can afterwards link in your main project's DITA Map.

  2. We still need to make changes to all DITA topics and replace all image hrefs with keyrefs. Oxygen has support for XML Refactoring actions and you can define custom XSLT scripts which can be applied to modify an entire set of topics. In the OXYGEN_INSTALL_DIR/refactoring folder you can add an XSLT script along with an XML description of the refactoring action. An XSLT script which would replace @href attributes on images with @keyref would look like this:
    <xsl:stylesheet xmlns:xsl=""
        <xsl:function name="f:getKeyref" as="xs:string">
            <xsl:param name="element" as="element()"/>
            <xsl:variable name="imageFile" select="tokenize(translate($element/@href, '\', '/'), '/')[last()]"/>
            <xsl:variable name="key" select="substring-before($imageFile, '.')"/>
            <xsl:value-of select="$key"/>
        <xsl:template match="node() | @*">
                <xsl:apply-templates select="node() | @*"/>
        <xsl:template match="image[@href and not(@keyref)]">
                <xsl:apply-templates select="@* except @href"/>
                <xsl:attribute name="keyref" select="f:getKeyref(.)"></xsl:attribute>
                <xsl:apply-templates select="node()"/>
    In the DITA Maps Manager view you can right click and choose Refactoring->XML Refactoring, then use your custom refactor action to modify all resources.

A set of samples, including the build file, XSLT stylesheets and refactor action XML descriptor can be found here:


  1. In my case the graphics were PNGs and I had to add format="png", otherwise I'd get "premature end of file" errors in Oxygen and the files were not recognized as graphics. Just in case ... Cheers, Franz-Josef

    1. Right, the XSLT stylesheet which produced the keydefs should have extracted the @href extension and use it as the @format attribute value.