DITA Configuration

ePublisher's DITA support allows for user-defined mappings between complex DITA element hierarchies and ePublisher styles. This configuration can be controlled at the source DITA map level or at the ePublisher Project and Target level. Finally, through the use of ePublisher Stationery, configurations can be maintained and deployed throughout your organization to all ePublisher Express and ePublisher AutoMap users.

Structured Elements and Styles

Before diving into the ePublisher configuration file, users should first understand how ePublisher processes DITA content.

At this time, ePublisher is a style-centric publishing system. The focus is on the layout and appearance of elements, not on structure.

Consider the following expanded DITA map:

  <map title="Styles and Structure">
    <topic>
      <title>Title Styles</title>
      <body>
        <section>
          <title>Section Title</title>
          <p>Sections are really great!</p>
        </section>
      </body>

      <topic>
        <title>Task Titles Triumph!</title>
        <body>
          <context>
            <p>Everything should be considered in context.</p>
          </context>
        </body>
      </topic>
    </topic>
  </map>

In this map, there are three <title> elements:

  <map> <topic> <title>
  <map> <topic> <body> <section> <title>
  <map> <topic> <topic> <title>

and two <p> elements:

  <map> <topic> <body> <section> <p>
  <map> <topic> <topic> <body> <context> <p>

In style based output formats (such as HTML and RTF), we might choose to treat certain elements with the same style. Here is one possible mapping:

Structure

Style

<map> <topic> <title>

Title

<map> <topic> <body> <section> <title>

Heading 1, Section 1

<map> <topic> <topic> <title>

Heading 1

<map> <topic> <body> <section> <p>

Section Body

<map> <topic> <topic> <body> <context> <p>

Topic Body

This mapping preserves all structure information one-for-one.

Now try "down mapping", converting multiple structures to a single style:

Structure

Style

<map> <topic> <title>

Title

<map> <topic> <body> <section> <title>

Heading 1

<map> <topic> <topic> <title>

Heading 1

<map> <topic> <body> <section> <p>

Body

<map> <topic> <topic> <body> <context> <p>

Body

Written another way:

Structure

Style

<map> <topic> <title>

Title

<title>[count(ancestor::<topic> or ancestor:<section>) > 1]

Heading 1

<p>

Body

Still further rewrites:

Structure

Style

<title>[count(ancestor::<topic>) = 1]

Title

<title>[count(ancestor::<topic> or ancestor:<section>) = 2]

Heading 1

<p>

Body

Mapping with XPath

This style mapping we have created seems nice, but ePublisher can't use it yet. Unless we convert it something ePublisher understands. In this case, we will convert the mapping to XPath expressions.

XPath Expression

Style

title[count(ancestor::topic) = 1]

Title

title[count(ancestor::topic or ancestor:section) = 2]

Heading 1

p

Body

That looks pretty good. Except DITA supports a little thing call "specialization". It means that I can give elements different names, yet process them the same way.

For example, the DITA element <task> is a specialization of the <topic> element. This is represented in DITA through DTDs in a class element. So when you see:

  <topic>
    ...
  </topic>

  <task>
    ...
  </task>

DITA sees:

  <topic class="- topic/topic ">
    ...
  </topic>

  <task class="- topic/topic task/task ">
    ...
  </task>

If you want to process a <task> element the same way as a <topic> element, you simply check for " topic/topic " in the @class attribute. And XPath expression to perform this test is:

  *[contains(@class, ' topic/topic ')]

Different behaviors for <task> elements can be introduced by checking for the " task/task " class substring:

  *[contains(@class, ' task/task ')]

Now let's rewrite our mapping to support DITA specialization:

XPath Expression

Style

*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ')]) = 1]

Title

*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ') or contains(@class, ' topic/section ')]) = 2]

Heading 1

*[contains(@class, ' topic/p ')]

Body

Wow! That's a pretty long-winded way of saying that! But, hey, now we get to use DITA, DITA Specialization, and ePublisher!

Configuring ePublisher

Great, now we know how to translate structures to styles. And we even know a technology, XPath, that can help us do that. What else does ePublisher need?

It needs the ePublisher DITA configuration file default.wwconfig of course!

<?xml version="1.0" encoding="UTF-8"?>
<DitaConfiguration version="1.0" xmlns="urn:WebWorks-Dita-Configuration-Schema"
                                 xmlns:wwditaconfig="urn:WebWorks-Dita-Configuration-Schema"
                                 xmlns:wwdoc="urn:WebWorks-Document-Schema"
                                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <Types>
  <Type match="//*[(contains(@class, ' map/topicref ')) and (string-length(@navtitle) &gt; 0)]" value="Paragraph" />
 </Types>

 <Styles>
  <Style match="//*[contains(@class, ' map/topicref ')]">
   <wwditaconfig:Head name="Topic Reference" />
  </Style>
 </Styles>
</DitaConfiguration>

ePublisher DITA Configuration File Structure

The ePublisher DITA configuration file allows ePublisher to answer the following questions:

  1. What style based objects does this structure represent? A paragraph? A character? A container? A table?
  2. What style name should be used for this structure?

Types

First, the <Types> section identifies what the structure represents. From our example, we would define the following types:

XPath Expression

Type

*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ')]) = 1]

Paragraph

*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ') or contains(@class, ' topic/section ')]) = 2]

Paragraph

*[contains(@class, ' topic/p ')]

Paragraph

*

Structure

Since all of the <title> elements are really just paragraphs, we can simplify this to:

XPath Expression

Type

*[contains(@class, ' topic/title ')]

Paragraph

*[contains(@class, ' topic/p ')]

Paragraph

*

Structure

Okay, so everything that is either a <title> element or a <p> element becomes a "Paragraph" and the rest become "Structure".

What if we had listed the "Structure" one first?

XPath Expression

Type

*

Structure

*[contains(@class, ' topic/title ')]

Paragraph

*[contains(@class, ' topic/p ')]

Paragraph

That would be bad, because everything in the document would be treated as "Structure"!

So why allow people to do this kind of thing? Well, perhaps we'd like to get crazy and convert DITA titles <section> elements to character styles:

XPath Expression

Type

*[contains(@class, ' topic/title ')][count(contains(@class, ' topic/section ')]) &gt; 0]

Character

*[contains(@class, ' topic/title ')]

Paragraph

*[contains(@class, ' topic/p ')]

Paragraph

*

Structure

We can be as specific as required and ePublisher will pick the first, best match.

Now, we'll return to our earlier (read simplier) example and translate it into ePublisher's required configuration file language:

XPath Expression

Type

*

Structure

*[contains(@class, ' topic/title ')]

Paragraph

*[contains(@class, ' topic/p ')]

Paragraph

 <Types>
  <Type match="//*[contains(@class, ' topic/title ')]" value="Paragraph" />
  <Type match="//*[contains(@class, ' topic/p ')]" value="Paragraph" />
 </Types>

Styles

We've already covered how to map structure to styles, so now we just need to show how this information is represented in the ePublisher configuration file:

XPath Expression

Style

*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ')]) = 1]

Title

*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ') or contains(@class, ' topic/section ')]) = 2]

Heading 1

*[contains(@class, ' topic/p ')]

Body

 <Styles>
  <Style match="//*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ')]) = 1]">
   <wwditaconfig:Head name="Title" />
  </Style>

  <Style match="//*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ') or contains(@class, ' topic/section ')]) = 2]">
   <wwditaconfig:Head name="Heading 1" />
  </Style>

  <Style match="//*[contains(@class, ' topic/p ')]">
   <wwditaconfig:Head name="Body" />
  </Style>
 </Styles>

Types and Styles Together

Perhaps now our little configuration file example will make a bit more sense:

<?xml version="1.0" encoding="UTF-8"?>
<DitaConfiguration version="1.0" xmlns="urn:WebWorks-Dita-Configuration-Schema"
                                 xmlns:wwditaconfig="urn:WebWorks-Dita-Configuration-Schema"
                                 xmlns:wwdoc="urn:WebWorks-Document-Schema"
                                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <Types>
  <Type match="//*[contains(@class, ' topic/title ')]" value="Paragraph" />
  <Type match="//*[contains(@class, ' topic/p ')]" value="Paragraph" />
 </Types>

 <Styles>
  <Style match="//*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ')]) = 1]">
   <wwditaconfig:Head name="Title" />
  </Style>

  <Style match="//*[contains(@class, ' topic/title ')][count(ancestor::*[contains(@class, ' topic/topic ') or contains(@class, ' topic/section ')]) = 2]">
   <wwditaconfig:Head name="Heading 1" />
  </Style>

  <Style match="//*[contains(@class, ' topic/p ')]">
   <wwditaconfig:Head name="Body" />
  </Style>
 </Styles>
</DitaConfiguration>

Overriding DITA Configurations

DITA configuration files can be overriding in four locations:

  1. Per source DITA map.
  2. Per project.
  3. Per format.
  4. Per target.

Per source DITA Map

If you have a DITA map file named mymap.ditamap, you can create a ePublisher configuration file with the base name of the original and use the .wwconfig extension.

You directory goes from:

  mymap.ditamap

to:

  mymap.ditamap
  mymap.wwconfig

NOTE:

This particular configuration file need only contain overrides or changes from the base default.wwconfig file.

Per project

Users can change the configuration of all DITA files in a project, across formats and targets, by creating a new default.wwconfig file in this location:

  <project directory>
    Formats
      Adapters
        xml
          scripts
            dita
              default.wwconfig

Per format

Users can change the configuration of all DITA files in a project for a particular format by creating a new default.wwconfig file in this location:

  <project directory>
    Formats
      <Format Name>
        Adapters
          xml
            scripts
              dita
                default.wwconfig

Per target

Users can change the configuration of all DITA files in a project for a single target by creating a new default.wwconfig file in this location:

  <project directory>
    Targets
      <Target Name>
        Adapters
          xml
            scripts
              dita
                default.wwconfig

Crazy Configurations

<Not yet complete.>

Some tips from experience

By Zoë Lawson

Occasionally, a <Style> may contain some wwdoc elements inside of the wwditaconfig:Head elements. These wwdoc elements provide formatting elements that override the Style Designer. For example, from the Style element which matches codeblock:

<wwditaconfig:Head name="{$
}">
     <wwdoc:Style>
          <wwdoc:Attribute name="font-family" value="Courier" />
          <wwdoc:Attribute name="white-space" value="pre" />
     </wwdoc:Style>
</wwditaconfig:Head>

The wwdoc:Attribute element defines that no matter what settings you have in the Style designer, always use Courier font and something that defines using ‘pre’-formatted white space. You may want to comment out the wwdoc:Style attributes to return control to the Style Designer.


The <wwdoc:Style> elements should not override Style Designer settings. Rather, they just set the default values to be used for that paragraph/character style. So, you should still be able to disable them, change them, etc., through the Style Designer.

Zoë, can you attach a test case showing this behavior?

-- BenAllums


--> -->

ValueError

list.remove(x): x not in list

If you want to report a bug, please save this page and attach it to your bug report.

Traceback

A problem occurred in a Python script. Here is the sequence of function calls leading up to the error, in the order they occurred.

  1. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/request/__init__.py in run (self=<MoinMoin.request.request_wsgi.Request object at 0x5f10490>)

    1. 1309 self.page.send_page()
    2. 1310 else:
    3. 1311 handler(self.page.page_name, self)
    4. 1312
    5. 1313 # every action that didn't use to raise MoinMoinFinish must call this now:
    • handler = <function do_show at 0x117a370>
    • self = <MoinMoin.request.request_wsgi.Request object at 0x5f10490>
    • self.page = <MoinMoin.Page.Page object at 0x5f25530>
    • self.page.page_name = u'HelpCenter/Tips/DITA/All Versions/DITA Configuration'
  2. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/action/__init__.py in do_show (pagename=u'HelpCenter/Tips/DITA/All Versions/DITA Configuration', request=<MoinMoin.request.request_wsgi.Request object at 0x5f10490>, content_only=0, count_hit=1, cacheable=1, print_mode=0)

    1. 251 count_hit=count_hit,
    2. 252 print_mode=print_mode,
    3. 253 content_only=content_only,
    4. 254 )
    5. 255
    • content_only = 0
  3. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/Page.py in send_page (self=<MoinMoin.Page.Page object at 0x5f25630>, **keywords={'content_only': 0, 'count_hit': 1, 'print_mode': 0})

    1. 1199 format_args=pi['formatargs'],
    2. 1200 do_cache=do_cache,
    3. 1201 start_line=pi['lines'])
    4. 1202
    5. 1203 # check for pending footnotes
    • start_line undefined
    • pi = {'acl': <MoinMoin.security.AccessControlList instance at 0x5df35d0>, 'format': 'wiki', 'formatargs': '', 'language': 'en', 'lines': 3}
  4. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/Page.py in send_page_content (self=<MoinMoin.Page.Page object at 0x5f25630>, request=<MoinMoin.request.request_wsgi.Request object at 0x5f10490>, body=u"= DITA Configuration =\nePublisher's DITA support...s=80, articleview=1, tablewidth=500, notify=1)>>\n", format='wiki', format_args='', do_cache=1, **kw={'start_line': 3})

    1. 1283
    2. 1284 if not (do_cache and self.canUseCache(Parser)):
    3. 1285 self.format(parser)
    4. 1286 else:
    5. 1287 try:
    • self = <MoinMoin.Page.Page object at 0x5f25630>
    • self.format = <bound method Page.format of <MoinMoin.Page.Page object at 0x5f25630>>
    • parser = <MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>
  5. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/Page.py in format (self=<MoinMoin.Page.Page object at 0x5f25630>, parser=<MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>)

    1. 1304 def format(self, parser):
    2. 1305 """ Format and write page content without caching """
    3. 1306 parser.format(self.formatter)
    4. 1307
    5. 1308 def execute(self, request, parser, code):
    • parser = <MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>
    • parser.format = <bound method Parser.format of <MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>>
    • self = <MoinMoin.Page.Page object at 0x5f25630>
    • self.formatter = <MoinMoin.formatter.text_html.Formatter instance at 0x5df35f8>
  6. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/parser/text_moin_wiki.py in format (self=<MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>, formatter=<MoinMoin.formatter.text_html.Formatter instance at 0x5df35f8>, inhibit_p=False)

    1. 1544
    2. 1545 # Scan line, format and write
    3. 1546 formatted_line = self.scan(line, inhibit_p=inhibit_p)
    4. 1547 self.request.write(formatted_line)
    5. 1548
    • formatted_line = u'<p class="line867"><hr /><p class="line874"> '
    • self = <MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>
    • self.scan = <bound method Parser.scan of <MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>>
    • line = u'<<PageComment2(markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1)>> '
    • inhibit_p = False
  7. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/parser/text_moin_wiki.py in scan (self=<MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>, line=u'<<PageComment2(markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1)>> ', inhibit_p=False)

    1. 1358 self.in_table or self.in_list):
    2. 1359 result.append(self.formatter.paragraph(1, css_class="line867"))
    3. 1360 result.append(self.replace(match, inhibit_p))
    4. 1361 end = match.end()
    5. 1362 lastpos = end
    • result = []
    • result.append = <built-in method append of list object at 0x5e18aa8>
    • self = <MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>
    • self.replace = <bound method Parser.replace of <MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>>
    • match = <_sre.SRE_Match object at 0x222a800>
    • inhibit_p = False
  8. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/parser/text_moin_wiki.py in replace (self=<MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>, match=<_sre.SRE_Match object at 0x222a800>, inhibit_p=False)

    1. 1402 # Get replace method and replace hit
    2. 1403 replace_func = getattr(self, '_%s_repl' % type)
    3. 1404 result.append(replace_func(hit, match.groupdict()))
    4. 1405 return ''.join(result)
    5. 1406 else:
    • result = []
    • result.append = <built-in method append of list object at 0x5e185d0>
    • replace_func = <bound method Parser._macro_repl of <MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>>
    • hit = u'markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1'
    • match = <_sre.SRE_Match object at 0x222a800>
    • match.groupdict = <built-in method groupdict of _sre.SRE_Match object at 0x222a800>
  9. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/parser/text_moin_wiki.py in _macro_repl (self=<MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>, word=u'markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1', groups={u'big': None, u'big_off': None, u'big_on': None, u'comment': None, u'dl': None, u'email': None, u'emph': None, u'emph_ib_or_bi': None, u'emph_ibb': None, u'emph_ibi': None, ...})

    1. 1325 if self.macro is None:
    2. 1326 self.macro = macro.Macro(self)
    3. 1327 return self.formatter.macro(self.macro, macro_name, macro_args, markup=groups.get('macro'))
    4. 1328 _macro_name_repl = _macro_repl
    5. 1329 _macro_args_repl = _macro_repl
    • self = <MoinMoin.parser.text_moin_wiki.Parser instance at 0x5d97030>
    • self.formatter = <MoinMoin.formatter.text_html.Formatter instance at 0x5df35f8>
    • self.formatter.macro = <bound method Formatter.macro of <MoinMoin.formatter.text_html.Formatter instance at 0x5df35f8>>
    • self.macro = <MoinMoin.macro.Macro instance at 0x5e18c60>
    • macro_name = u'PageComment2'
    • macro_args = u'markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1'
    • markup undefined
    • groups = {u'big': None, u'big_off': None, u'big_on': None, u'comment': None, u'dl': None, u'email': None, u'emph': None, u'emph_ib_or_bi': None, u'emph_ibb': None, u'emph_ibi': None, ...}
    • groups.get = <built-in method get of dict object at 0x1d1e030>
  10. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/formatter/__init__.py in macro (self=<MoinMoin.formatter.text_html.Formatter instance at 0x5df35f8>, macro_obj=<MoinMoin.macro.Macro instance at 0x5e18c60>, name=u'PageComment2', args=u'markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1', markup=u'<<PageComment2(markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1)>>')

    1. 308 # call the macro
    2. 309 try:
    3. 310 return macro_obj.execute(name, args)
    4. 311 except ImportError, err:
    5. 312 errmsg = unicode(err)
    • macro_obj = <MoinMoin.macro.Macro instance at 0x5e18c60>
    • macro_obj.execute = <bound method Macro.execute of <MoinMoin.macro.Macro instance at 0x5e18c60>>
    • name = u'PageComment2'
    • args = u'markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1'
  11. /webworks/wiki/lib/python2.5/site-packages/MoinMoin/macro/__init__.py in execute (self=<MoinMoin.macro.Macro instance at 0x5e18c60>, macro_name=u'PageComment2', args=u'markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1')

    1. 126 else:
    2. 127 raise ImportError("Cannot load macro %s" % macro_name)
    3. 128 return execute(self, args)
    4. 129
    5. 130 def _m_lang(self, text):
    • execute = <function execute at 0x4777ab0>
    • self = <MoinMoin.macro.Macro instance at 0x5e18c60>
    • args = u'markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1'
  12. /Volumes/Projects-Wiki/wiki.wiki/data/plugin/macro/PageComment2.py in execute (macro=<MoinMoin.macro.Macro instance at 0x5e18c60>, args=u'markup=1, newerfirst=1, rows=4, cols=80, articleview=1, tablewidth=500, notify=1')

  13. /Volumes/Projects-Wiki/wiki.wiki/data/plugin/macro/PageComment2.py in setglobalvalues (macro=<MoinMoin.macro.Macro instance at 0x5e18c60>)

ValueError

list.remove(x): x not in list

  • args = ('list.remove(x): x not in list',)
  • message = 'list.remove(x): x not in list'

System Details

  • Date: Wed, 23 May 2012 17:46:19 +0000
  • Platform: Darwin hulahut 10.8.0 Darwin Kernel Version 10.8.0: Tue Jun 7 16:32:41 PDT 2011; root:xnu-1504.15.3~1/RELEASE_X86_64 x86_64
  • Python: Python 2.5.4 (/webworks/wiki/bin/python)
  • MoinMoin: Release 1.8.4 (release)