Using Parameter Entity Overrides to Eliminate Mixed Content From Stuctural Elements
Blog entry: Submitted by rnthomas on Mon, 2006-06-19 22:36.
Allowing mixed content (text and inline tags) to be direct children of structural elements such as section creates usability problems during authoring and adds complexity to transformations. Mixed content in these contexts is not appropriate for authoring. However, this shortcoming does not appear to be the result of an oversight on the part of the DITA architects. Instead, it appears to be an engineering tradeoff that was made facilitate specialization. Allowing mixed content to appear adds a great deal of flexibility to the information architect's toolbox when specializing.
As an information architect, I am free to write specializations that use more restrictive content models than those that are found in concept, reference, and task. Unfortunately, this solution creates a new dilemma. Suppose that I like everything about the task topic except for the fact that users can enter mixed content in inappropriate places such as directly under prereq.
One possible solution is to create a specialization that is parallel to task, call it bob-task, and then create bob-.* structural elements that are parallel those found in task, except for mixed content. There are a number of problems with this approach:
+ It is maintenance intensive
+ It is aesthetically unappealing (i.e., it looks stupid)
+ It creates training problems
Another solution is to hack topic.mod and redefine content model parameter entities such as %section.cnt; so that they no longer allow mixed content. The problem with this is that you've now invalidated any specializations that have taken advantage of mixed content in structural elements.
After trying both of these solutions, and being dissatisfied with the results, it occurred to me that I could create a new shell DTD for each topic type and override the content model parameter entities there before calling in topic.mod. (When a parameter entity is defined more than once in a DTD, the definition that the parser finds first is the one that gets used.) For example, in the case of task, I call in my parameter entity definitions, then topic.mod, and finally task.mod. All of the task's structural tags are available. The only difference is that mixed content no longer shows up in structural elements. The only down-side to this approach is that I have to create a new public identifier for each topic-type because strictly speaking they are no longer the same as the OASIS DITA topics -- they are now subsets. The end result is an improved authoring environment that changes the DITA framework through a benign mechanism (i.e., shell DTDs).
The mechanics for this are straightforward. In my case, I chose to put all of my parameter entity overrides and their dependent entity definitions in a separate file, and then call that file into each of my shell DTDs. The only glitch that I encountered arose with the choice element in task. For some reason choice uses an explicit content model rather than the %listitem.cnt; parameter entity which is structurally equivalent; I believe this is a minor implementation error in DITA.
Sample code follows.
Bob Thomas
Tagsmiths, LLC
As an information architect, I am free to write specializations that use more restrictive content models than those that are found in concept, reference, and task. Unfortunately, this solution creates a new dilemma. Suppose that I like everything about the task topic except for the fact that users can enter mixed content in inappropriate places such as directly under prereq.
One possible solution is to create a specialization that is parallel to task, call it bob-task, and then create bob-.* structural elements that are parallel those found in task, except for mixed content. There are a number of problems with this approach:
+ It is maintenance intensive
+ It is aesthetically unappealing (i.e., it looks stupid)
+ It creates training problems
Another solution is to hack topic.mod and redefine content model parameter entities such as %section.cnt; so that they no longer allow mixed content. The problem with this is that you've now invalidated any specializations that have taken advantage of mixed content in structural elements.
After trying both of these solutions, and being dissatisfied with the results, it occurred to me that I could create a new shell DTD for each topic type and override the content model parameter entities there before calling in topic.mod. (When a parameter entity is defined more than once in a DTD, the definition that the parser finds first is the one that gets used.) For example, in the case of task, I call in my parameter entity definitions, then topic.mod, and finally task.mod. All of the task's structural tags are available. The only difference is that mixed content no longer shows up in structural elements. The only down-side to this approach is that I have to create a new public identifier for each topic-type because strictly speaking they are no longer the same as the OASIS DITA topics -- they are now subsets. The end result is an improved authoring environment that changes the DITA framework through a benign mechanism (i.e., shell DTDs).
The mechanics for this are straightforward. In my case, I chose to put all of my parameter entity overrides and their dependent entity definitions in a separate file, and then call that file into each of my shell DTDs. The only glitch that I encountered arose with the choice element in task. For some reason choice uses an explicit content model rather than the %listitem.cnt; parameter entity which is structurally equivalent; I believe this is a minor implementation error in DITA.
Sample code follows.
Bob Thomas
Tagsmiths, LLC
- rnthomas's blog
- Login to post comments
- 10063 reads
managing overrides as constraints
It makes perfect sense to restrict content models either to simplify for some authors (as with your <section> example) or to enforce best practices (for instance, to make <shortdesc> mandatory). A similar need exists to define enumerations for attributes.
For DITA 1.2, a constraints mechanism has been proposed that would (in essence) introduce a new architectural feature for applying restrictions to content models or attribute values without specializing the element.
The challenge is not so much to override the base DTD or Schema modules but to declare and manage these constraint modules within the architecture so that they can be shared among users, detected by processes, incorporated in generalization and respecialization, and so on.
In short, I'd agree that this issue is a good one for the TC to investigate once DITA 1.1 is out the door.
Thanks,
Erik Hennum
The attachments seem to be
*************************************************************
BEGIN SHELL DTD (tagsmiths-task.dtd):
*************************************************************
<!-- Refer to this file by the following public identifier
PUBLIC "-//Tagsmiths//DTD DITA Task//EN"
Delivered as file "tagsmiths-task.dtd" -->
<!-- ============================================================= -->
<!-- SYSTEM: Darwin Information Typing Architecture (DITA) -->
<!-- -->
<!-- PURPOSE: DTD to describe DITA Tasks -->
<!-- -->
<!-- ORIGINAL CREATION DATE: -->
<!-- March 2001 -->
<!-- -->
<!-- (C) Copyright OASIS Open 2005. -->
<!-- (C) Copyright IBM Corporation 2001, 2004. -->
<!-- All Rights Reserved. -->
<!-- ============================================================= -->
<!-- ============================================================= -->
<!-- DOMAIN ENTITY DECLARATIONS -->
<!-- ============================================================= -->
<!ENTITY % ui-d-dec PUBLIC
"-//OASIS//ENTITIES DITA User Interface Domain//EN"
"uiDomain.ent" >
%ui-d-dec;
<!ENTITY % hi-d-dec PUBLIC
"-//OASIS//ENTITIES DITA Highlight Domain//EN"
"highlightDomain.ent" >
%hi-d-dec;
<!ENTITY % pr-d-dec PUBLIC
"-//OASIS//ENTITIES DITA Programming Domain//EN"
"programmingDomain.ent" >
%pr-d-dec;
<!ENTITY % sw-d-dec PUBLIC
"-//OASIS//ENTITIES DITA Software Domain//EN"
"softwareDomain.ent" >
%sw-d-dec;
<!ENTITY % ut-d-dec PUBLIC
"-//OASIS//ENTITIES DITA Utilities Domain//EN"
"utilitiesDomain.ent" >
%ut-d-dec;
<!-- ============================================================= -->
<!-- DOMAIN EXTENSIONS -->
<!-- ============================================================= -->
<!-- One for each extended base element, with
the name of the domain(s) in which the
extension was declared -->
<!ENTITY % pre "pre | %pr-d-pre; | %sw-d-pre; |
%ui-d-pre;" >
<!ENTITY % keyword "keyword | %pr-d-keyword; | %sw-d-keyword; |
%ui-d-keyword;" >
<!ENTITY % ph "ph | %pr-d-ph; | %sw-d-ph; |
%hi-d-ph; | %ui-d-ph; |
%ai-d-ph;" >
<!ENTITY % fig "fig | %pr-d-fig; | %ut-d-fig;" >
<!ENTITY % dl "dl | %pr-d-dl;" >
<!-- ============================================================= -->
<!-- TOPIC NESTING OVERRIDE -->
<!-- ============================================================= -->
<!-- Redefine the infotype entity to exclude
other topic types and disallow nesting -->
<!ENTITY % task-info-types
"task" >
<!-- ============================================================= -->
<!-- DOMAINS ATTRIBUTE OVERRIDE -->
<!-- ============================================================= -->
<!-- Must be declared ahead of the DTDs, which
puts @domains first in order -->
<!ENTITY included-domains
"&ui-d-att; &hi-d-att; &pr-d-att; &sw-d-att;
&ut-d-att;" >
<!-- ============================================================= -->
<!-- TOPIC ELEMENT INTEGRATION -->
<!-- ============================================================= -->
<!-- Insert Tagsmiths parameter entity overrides -->
<!ENTITY % tagsmiths-overrides PUBLIC
"-//Tagsmiths//ENTITIES DITA overrides//EN"
"tagsmiths-overrides.ent" >
%tagsmiths-overrides;
<!-- Embed topic to get generic elements -->
<!ENTITY % topic-type PUBLIC
"-//OASIS//ELEMENTS DITA Topic//EN"
"topic.mod" >
%topic-type;
<!-- Embed task to get specific elements -->
<!ENTITY % task-typemod PUBLIC
"-//OASIS//ELEMENTS DITA Task//EN"
"task.mod" >
%task-typemod;
<!-- ============================================================= -->
<!-- DOMAIN ELEMENT INTEGRATION -->
<!-- ============================================================= -->
<!ENTITY % ui-d-def PUBLIC
"-//OASIS//ELEMENTS DITA User Interface Domain//EN"
"uiDomain.mod" >
%ui-d-def;
<!ENTITY % hi-d-def PUBLIC
"-//OASIS//ELEMENTS DITA Highlight Domain//EN"
"highlightDomain.mod" >
%hi-d-def;
<!ENTITY % pr-d-def PUBLIC
"-//OASIS//ELEMENTS DITA Programming Domain//EN"
"programmingDomain.mod" >
%pr-d-def;
<!ENTITY % sw-d-def PUBLIC
"-//OASIS//ELEMENTS DITA Software Domain//EN"
"softwareDomain.mod" >
%sw-d-def;
<!ENTITY % ut-d-def PUBLIC
"-//OASIS//ELEMENTS DITA Utilities Domain//EN"
"utilitiesDomain.mod" >
%ut-d-def;
<!-- ============= End Tagsmiths DITA Task DTD ================= -->
*************************************************************
END SHELL DTD
*************************************************************
*************************************************************
BEGIN ENTITY OVERRIDE FILE (tagsmiths-overrides.ent):
*************************************************************
<!--
These entity names match those found in topic.mod. These new definitions
have simply removed #PCDATA and %basic.ph; from each content model.
This file must be called into the specialized-topic DTD before topic.mod
is called.
-rnt 28apr06
-->
<!-- Refer to this file by the following public identifier
PUBLIC "-//Tagsmiths//ENTITIES DITA overrides//EN"
-->
<!-- The next 50 or 60 lines are an exact copy from topic.mod.
This copy was necessary to provide definitions for the
parameter entities that are used within the .cnt parameter
entity definitions.
-->
<!-- START OF EXACT COPY from topic.mod -->
<!-- Definitions of declared elements -->
<!ENTITY % topicDefns PUBLIC
"-//OASIS//ENTITIES DITA Topic Definitions//EN"
"topicDefn.ent" >
%topicDefns;
<!-- ============================================================= -->
<!-- ENTITY DECLARATIONS FOR ATTRIBUTE VALUES -->
<!-- ============================================================= -->
<!-- ============================================================= -->
<!-- COMMON ATTLIST SETS -->
<!-- ============================================================= -->
<!-- Phrase/inline elements of various classes -->
<!ENTITY % basic.ph "%ph; | %term; | %xref; | %cite; | %q; |
%boolean; | %state; | %keyword; | %tm;" >
<!-- Elements common to most body-like contexts -->
<!ENTITY % basic.block "%p; | %lq; | %note; | %dl; | %ul; | %ol;|
%sl; | %pre; | %lines; | %fig; | %image; |
%object; | %table; | %simpletable;">
<!-- class groupings to preserve in a schema -->
<!ENTITY % basic.phandblock "%basic.ph; | %basic.block;" >
<!-- Exclusions: models modified by removing excluded content -->
<!ENTITY % basic.ph.noxref
"%ph;|%term;| %q;|%boolean;|%state;|%keyword;|%tm;">
<!ENTITY % basic.ph.notm
"%ph;|%term;|%xref;|%cite;|%q;|%boolean;|%state;|%keyword;">
<!ENTITY % basic.block.notbl
"%p;|%lq;|%note;|%dl;|%ul;|%ol;|%sl;|%pre;|%lines;|%fig;|%image;|%object;">
<!ENTITY % basic.block.nonote
"%p;|%lq;| %dl;|%ul;|%ol;|%sl;|%pre;|%lines;|%fig;|%image;|%object;|%table;|%simpletable;">
<!ENTITY % basic.block.nopara
" %lq;|%note;|%dl;|%ul;|%ol;|%sl;|%pre;|%lines;|%fig;|%image;|%object;|%table;|%simpletable;">
<!ENTITY % basic.block.nolq
"%p;| %note;|%dl;|%ul;|%ol;|%sl;|%pre;|%lines;|%fig;|%image;|%object;|%table;|%simpletable;">
<!ENTITY % basic.block.notbnofg
"%p;|%lq;|%note;|%dl;|%ul;|%ol;|%sl;|%pre;|%lines;| %image;|%object;">
<!ENTITY % basic.block.notbfgobj
"%p;|%lq;|%note;|%dl;|%ul;|%ol;|%sl;|%pre;|%lines;| %image;">
<!ENTITY % txt.incl '%draft-comment;|%required-cleanup;|%fn;|%indextermref;|%indexterm;'>
<!-- END OF EXACT COPY from topic.mod -->
<!-- BEGIN TAGSMITHS MODIFICATIONS -->
<!-- This set has #PCDATA and the %basic.ph; parameter entity removed -->
<!ENTITY % section.cnt "%basic.block; | %title; | %txt.incl;">
<!ENTITY % section.notitle.cnt "%basic.block; | %txt.incl;">
<!ENTITY % listitem.cnt "%basic.block; |%itemgroup;| %txt.incl;">
<!ENTITY % itemgroup.cnt "%basic.block; | %txt.incl;">
<!ENTITY % note.cnt "%basic.block.nonote; | %txt.incl;">
<!ENTITY % longquote.cnt "%basic.block.nolq; | %txt.incl;">
<!ENTITY % tblcell.cnt "%basic.block.notbl; | %txt.incl;">
<!ENTITY % desc.cnt "%basic.block.notbfgobj;">
*************************************************************
END ENTITY OVERRIDE FILE
*************************************************************