Edit online

Replacing Direct Image References with Key References in a DITA Project.

Read time: 5 minute(s)
Suppose that you have a large DITA project and all the image references in your topics are direct references, using the @href attribute like this:
<image href="../../images/Iris_sanguinea.jpg" scale="50"/>
For better scalability and reuse possibilities, suppose 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 also manually building a DITA map that maps the image file name to the image location.

This blog post will try to describe some steps that you will help you to automate this change in your project:
  1. The first big step is to generate the DITA Map that 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">
    <map>
    ….…....
    <keydef href="Iris_sanguinea.jpg" keys="Iris_sanguinea.jpg"/>
    …...
    </map>
    We will assume that all images are placed in an images folder and we can create an ANT build file that 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}"/>
        </xslt>
    </project>
    The XSLT stylesheet createKeyrefsMap.xsl is responsible for creating the mapping DITA map:
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="1.0">
        <xsl:param name="filesList"/>
        <xsl:output doctype-public="-//OASIS//DTD DITA Map//EN" doctype-system="map.dtd" indent="yes"/>
        <xsl:template match="/">
            <map>
                <xsl:call-template name="tokenizeString">
                    <xsl:with-param name="list" select="$filesList"/>
                </xsl:call-template>
            </map>
        </xsl:template>
        <xsl:template name="tokenizeString">
            <xsl:param name="list"/>
            <xsl:param name="delimiter" select="';'"/>
            <xsl:choose>
                <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)"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <keydef href="{$list}" keys="{$list}"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    </xsl:stylesheet>

    After this step you will have a new DITA map with all image mappings and afterwards you can link it 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 that 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 that would replace @href attributes on images with @keyref would look like this:
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="2.0"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:f="http://www.oxygenxml.com/ns/functions">
        <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:function>
        <xsl:template match="node() | @*">
            <xsl:copy>
                <xsl:apply-templates select="node() | @*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="image[@href and not(@keyref)]">
            <xsl:copy>
                <xsl:apply-templates select="@* except @href"/>
                <xsl:attribute name="keyref" select="f:getKeyref(.)"></xsl:attribute>
                <xsl:apply-templates select="node()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet> 
    You can right-click anywhere in the DITA Maps Manager view and choose Refactoring->XML Refactoring, then use your custom refactoring action to modify all resources.

A set of samples, including the build file, XSLT stylesheets, and refactoring action XML descriptor can be found here:https://www.oxygenxml.com/forum/files/batchImageHrefToKeyref.zip.