Mapping XML Elements to InDesign Paragraph and Character Styles

You define the mapping of elements to specific character and paragraph styles using simple XSLT templates.

Unlike the Word-to-DITA transformation framework, which uses a separate configuration file to define the mapping of Word paragraphs to DITA elements, the DITA-to-InDesign process uses XSLT modules with very simple XSLT templates. The reason for this is that the only way to fully support mapping arbitrary elements in context to styles is to use XPath or something equivalent to it and it would be harder to define and implement a separate configuration specification that gave you that power than it would to simply code the XSLT directly.

The base DITA-to-InDesign transform includes a module named elem2styleMapper.xsl, which defines the default mapping for DITA elements to paragraph and character style names. However, it is unlikely that this mapping will work for some or even any of your content, since the style names need to match your InDesign templates. Thus you will likely need to create your own element-to-style mapper module that extends or overrides the base mapping, either as an extension to the DITA2InDesign plugin or via a custom top-level transform that includes your custom mapper as well as the base DITA2InDesign transform.

The element-to-style mapper looks like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:local="urn:local-functions"
      xmlns:df="http://dita2indesign.org/dita/functions"
      xmlns:e2s="http//dita2indesign.org/functions/element-to-style-mapping"
      exclude-result-prefixes="xs local df e2s"
      version="2.0">
  
  <!-- Element-to-style mapper
    
    This module provides the base implementation for
    the "style-map" modes, which map elements in context
    to InDesign style names (paragraph, character, frame,
    object, table).
    
    Copyright (c) 2009 Really Strategies, Inc.
    
    NOTE: This material is intended to be donated to the RSI-sponsored
    DITA2InDesign open-source project.
  -->
  <xsl:import href="../lib/dita-support-lib.xsl"/>
  <xsl:import href="lib/incx_generation_util.xsl"/>
  
  <xsl:template match="/*[df:class(., 'topic/topic')]/*[df:class(., 'topic/title')]" 
    mode="style-map-pstyle">
    <xsl:sequence select="'Topic Title 1'"/>
  </xsl:template>
  
  <xsl:template match="/*[df:class(., 'topic/topic')]/*[df:class(., 'topic/topic')]/*[df:class(., 'topic/title')]" 
    mode="style-map-pstyle">
    <xsl:sequence select="'Topic Title 2'"/>
  </xsl:template>

  ...

  <xsl:template match="*[df:class(., 'topic/ph')]" 
    mode="style-map-cstyle" priority="0.75">
    <xsl:sequence select="'[No character style]'"/>
  </xsl:template>
  
  <xsl:template match="*[df:class(., 'topic/cite')]" 
    mode="style-map-cstyle">
    <xsl:sequence select="'italic'"/>
  </xsl:template>

  ...

</xsl:stylesheet>

The module provides templates for two different XSLT modes; style-map-pstyle and style-map-cstyle.

The style-map-pstyle templates map elements in context to paragraph style names. The style-map-cstyle templates map elements to character style names. Note that the same XML element may map to both paragraphs and character runs in different contexts.

Each template does nothing other than produce a literal string that is the InDesign style name.

Looking at the first highlighted template above, the parts are:
Component Meaning
match="/*[df:class(., 'topic/topic')]/*[df:class(., 'topic/title')]" The match statement that matches a specific context. The value of the @@match attribute is an XPath expression. Here it uses the DITA Support Library "df:class" function to match on elements based on their DITA @@class values rather than their tagnames, e.g., title within a topic that is the root of the document (as indicated by the leading "/" in the XPath expression).
mode="style-map-pstyle" The XSLT mode this template is used in, in this case "style-map-pstyle", indicating a template that maps to a paragraph style name. The other possible mode is "style-map-cstyle"
<xsl:sequence select="'Topic Title 1'"/> An XSLT 2 sequence constructor used to produce the literal string "Topic Title 1" per the value of the @@select attribute. Note the single quotes within the double quotes of the attribute specification. The style name string is the style display name as it appears in the InDesign user interface.

The second highlighted example follows exactly the same pattern, differing only in the name of the mode ("style-map-cstyle") .

Your custom element-to-style mappings should follow the same pattern, differing only in the details of the @@match expression and the style name produced.

The only other thing you may need to add is a @@priority attribute when you need to have templates for more-specialized elements that would otherwise match on a template for the specialization's ancestor types. In that case, you must specify a @@priority attribute on the <xsl:template> element with a value greater than 1, e.g., <xsl:template priority="10" ... or whatever number ensures the template will match before other templates the element might have matched on.

For example, say your vocabulary includes a specialization of <ph> named "foo" and a specialization of "foo" named "bar". You want <foo> to map to the paragraph style "Foo" but <bar> to map to the paragraph style "Bar". You start by creating these two match templates:
  <xsl:template match="*[df:class(., 'foodomain-d/foo')]" 
    mode="style-map-pstyle">
    <xsl:sequence select="'Foo'"/>
  </xsl:template>

  <xsl:template match="*[df:class(., 'bardomain-d/bar')]" 
    mode="style-map-pstyle">
    <xsl:sequence select="'Bar'"/>
  </xsl:template>

If you used these templates as is you would get "ambiguous rule match" messages for <bar> elements because <bar> is a specialization of <foo> and thus matches both on a check for foo as well as bar (that is, the @@class value for <bar> would be something like "+ topic/ph foodomain-d/foo bardomain-d/bar ").

To remove the ambiguity you would add a @@priority attribute to the template for <bar>, forcing it to match first:
  <xsl:template match="*[df:class(., 'bardomain-d/bar')]" 
    priority="10"
    mode="style-map-pstyle">
    <xsl:sequence select="'Bar'"/>
  </xsl:template>

Now when you run the transform all the <bar> elements will map to the style 'Bar' as you intended.

The @@priority value of "0.75" for the template for the <ph> element in the example above puts it's priority below the default priority of "1", ensuring that the template for <ph> will not interfere with any templates for specializations of <ph>.

To create your own mapping module, simply copy the base elem2styleMap.xsl file to a new location, normally a Toolkit plugin for your extensions, remove all the templates you don't want to override, modify the ones you do, and add any additional mappings you need.

If these mappings should be global to all InCopy generations in your environment you can use the module as a Toolkit-provided extension to the base DITA2InDesign transformation type.

If, as is more likely, your mappings are for a specific use and not global to all InCopy transforms, then you must create a new plugin with a new top-level transform that includes your mapping module and the base dita2indesign.xsl transform.