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) > 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:
- What style based objects does this structure represent? A paragraph? A character? A container? A table?
- 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 ')]) > 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:
- Per source DITA map.
- Per project.
- Per format.
- 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.
/webworks/wiki/lib/python2.5/site-packages/MoinMoin/request/__init__.py in run (self=<MoinMoin.request.request_wsgi.Request object at 0x5f10490>)
- 1309 self.page.send_page()
- 1310 else:
- 1311 handler(self.page.page_name, self)
- 1312
- 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'
/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)
- 251 count_hit=count_hit,
- 252 print_mode=print_mode,
- 253 content_only=content_only,
- 254 )
- 255
- content_only = 0
/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})
- 1199 format_args=pi['formatargs'],
- 1200 do_cache=do_cache,
- 1201 start_line=pi['lines'])
- 1202
- 1203 # check for pending footnotes
- start_line undefined
- pi = {'acl': <MoinMoin.security.AccessControlList instance at 0x5df35d0>, 'format': 'wiki', 'formatargs': '', 'language': 'en', 'lines': 3}
/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})
- 1283
- 1284 if not (do_cache and self.canUseCache(Parser)):
- 1285 self.format(parser)
- 1286 else:
- 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>
/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>)
- 1304 def format(self, parser):
- 1305 """ Format and write page content without caching """
- 1306 parser.format(self.formatter)
- 1307
- 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>
/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)
- 1544
- 1545 # Scan line, format and write
- 1546 formatted_line = self.scan(line, inhibit_p=inhibit_p)
- 1547 self.request.write(formatted_line)
- 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
/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)
- 1358 self.in_table or self.in_list):
- 1359 result.append(self.formatter.paragraph(1, css_class="line867"))
- 1360 result.append(self.replace(match, inhibit_p))
- 1361 end = match.end()
- 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
/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)
- 1402 # Get replace method and replace hit
- 1403 replace_func = getattr(self, '_%s_repl' % type)
- 1404 result.append(replace_func(hit, match.groupdict()))
- 1405 return ''.join(result)
- 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>
/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, ...})
- 1325 if self.macro is None:
- 1326 self.macro = macro.Macro(self)
- 1327 return self.formatter.macro(self.macro, macro_name, macro_args, markup=groups.get('macro'))
- 1328 _macro_name_repl = _macro_repl
- 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>
/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)>>')
- 308 # call the macro
- 309 try:
- 310 return macro_obj.execute(name, args)
- 311 except ImportError, err:
- 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'
/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')
- 126 else:
- 127 raise ImportError("Cannot load macro %s" % macro_name)
- 128 return execute(self, args)
- 129
- 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'
/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')
/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)
