How to cite this paper
Kimber, Eliot, and George Bina. “RELAX NG and DITA: An Almost Perfect Match.” Presented at Balisage: The Markup Conference 2014, Washington, DC, August 5 - 8, 2014. In Proceedings of Balisage: The Markup Conference 2014. Balisage Series on Markup Technologies, vol. 13 (2014). https://doi.org/10.4242/BalisageVol13.Kimber01.
Balisage: The Markup Conference 2014
August 5 - 8, 2014
Balisage Paper: RELAX NG and DITA: An Almost Perfect Match
Kimber Eliot
Eliot has been doing generalized markup longer than most humans have been
alive. Eliot's most recent professional focus is on the application of the DITA
standard to the requirements of professional publishers. Eliot is a founding member
of the OASIS DITA Technical Committee and active contributor to the DITA standard.
Eliot maintains the DITA For Publishers open source project. When not wrangling
tags to his will, Eliot trains in Aikido and skateboards when he can. Eliot lives
in Austin, Texas.
Bina George
George is founder of SyncroSoft, makers of the oXygenXML product.
George is a mathematician by training. George lives and works in Criova,
Romania. When not contributing to open-source projects, George enjoys
travel with his family and taking selfies of himself working in
exotic locations.
Copyright © 2014 George Bina and Eliot Kimber
Abstract
The DITA vocabulary architecture defines a formal and controlled mechanism for configuring
and extending the base DITA vocabulary. The architecture is independent of any XML
document grammar facility in that DITA only requires that document instances exhibit
specific attributes that serve to declare the document's effective document type (set
of vocabulary and constraint modules) and each element's relationship to its base
element types (specialization hierarchy). However, practical authoring and management
of DITA documents requires the use of some form of document grammar, e.g. a DTD, XML
schema, etc. While the DITA standard defines specific coding patterns for implementing
DITA vocabulary and constraint modules and for integrating those modules into document
type shells, DITA users find both the DTD and XSD implementation details difficult
and challenging due to the syntax and semantics of both grammar facilities. Through
DITA version 1.2, the DITA standard recognized only DTDs and XSDs as conforming DITA
grammar languages and the DITA Technical Committee provided both DTD and XSD versions
of the DITA modules and document type shells. One the authors (George Bina) discovered
that RELAX NG provided significant advantages over both DTD and XSD grammars, significantly
simplifying both the task of integrating modules into working document types and defining
vocabulary and constraint modules. Specific features of RELAX NG make it the best
match to DITA's vocabulary architecture of any current XML document grammar facility.
This paper discusses the general requirements defined by the DITA vocabulary architecture,
the challenges presented by the DTD and XSD grammar facilities, and how RELAX NG addresses
all those requirements. We also present some suggestions for improvements in RELAX
NG that would remove the few places where RELAX NG is not optimal for DITA's requirements.
Table of Contents
- Introduction
- DITA Modular Vocabulary Requirements
- Challenges Posed by DTD Syntax
- Challenges Posed by XML Schema
-
- XSD Redefine Facility
- DITA 1.2 Group Design and XSD
- Working Around Redefine Limitations: Indirection in Sequence Groups
- Declarations for Integrating Domain Element Types in XSD Document Type Shells
- How RELAX NG Addresses DITA Requirements
-
- RELAX NG is a Good Match to DTDs
- Modules are Self Integrating
- DTD and XSD Generation
- Conclusions and Future Work
Introduction
The OASIS Darwin Information Typing Architecture standard (DITA) defines a unique approach to the definition and management of XML document
vocabularies. Rather than defining a monolithic set of element types and attributes
that can then be modified or added to without constraint, DITA defines a formal architecture
consisting of a set of invariant base vocabulary "modules" comprising the base standard
DITA vocabulary. These modules are invariant in the sense that they are not intended
to be modified directly but only through specific configuration and extension facilities
as defined by the DITA standard. In particular, modules may not be modified in a way
that makes them less constrained than the base definition. All copies of a given module
version in time should be identical.
A given set of modules represents a unique "DITA document type". Two DITA documents
that use the same modules have the same DITA document type. Note that this notion
of "DITA document type" is independent of the use of any particular document grammar
associated with the document: it is only necessary for a document to declare the set
of modules it uses, which is done with the DITA-defined @domains attribute on the
document root element. The value of the @domains attribute is simply a list of modules:
<topic domains="(topic topic) (topic hi-d) (topic pr-d)">
.
Likewise, each DITA element declares it's relationship to the base DITA vocabulary
through the the DITA-defined @class attribute, which enumerates the element's ancestry
as a sequence of module/tagname pairs: <steps class="- topic/ol task/steps ">
. For the <steps> element, the @class value can be read as "the <steps> element, defined
within the "task" topic type module, is a specialization of the <ol> element defined
in the "topic" topic type module. That is, it reflects the type hierarchy "steps is-a
ol".
Given a DITA document with the @domains and@class attributes present the document
is fully processable by any DITA-aware processor. In practice, however, the @domains
and @class values are defined as attribute default values in some governing grammar
and omitted from document instances. Thus, while the DITA standard does not require
the use of grammars with conforming DITA documents, practical considerations effectively
require grammars to enable population of the @domains and @class values, general document
validation, authoring support, and so on.
The DITA standard defines specific coding requirements for the grammar types recognized
by the DITA standard. These coding requirements ensure consistency across all conforming
DITA vocabularies and thus facilitate interchange of vocabulary modules.
DITA vocabulary implementation involves three component types:
-
Vocabulary modules, which define element and attribute types. Vocabulary modules are
either "structural", defining new map or topic types, or "domain", defining element
types that may be used in any map or topic type as appropriate ("mix-in" elements).
Every DITA document is either a map or a topic and therefore uses at least a single
structural module. Vocabulary modules must be coded in such a way as to enable appropriate
extension and constraint through separate modules. That is, it must be possible to
modify the base content model and attribute list declarations as allowed by the DITA
architecture without directly modifying the vocabulary module files themselves.
-
Constraint modules, which constrain content modules or attributes for elements. Constraints
are implemented by redefining or overriding base content model and attribute list
declarations.
-
Document type shells, which "integrate" vocabulary and constraint modules to implement
specific DITA document types. Document type shells are logically just inclusion lists
of the vocabulary and constraint modules used by the document type. In particular,
the list of included modules should match the set of modules named by the document's
@domains attribute.
The implementation challenge for DITA vocabulary, constraint, and document type shell
authors is that neither DTD nor XSD are a particularly good match syntactically or
semantically to DITA's requirements. DTDs require the use of parameter entities, which
leads to convoluted and difficult-to-debug document type shells. XSD 1.0's limited
and highly-constrained facilities for content model and group redefinition require
various forms of indirection not inherent in the semantics of the DITA element types
nor required in the DTD implementation of the equivalent vocabulary. The DITA user
community, even highly-experienced practitioners, find implementing and maintaining
both DTD and XSD vocabulary modules tedious and challenging.
While the issues with DTD mostly stem from the difficulty in debugging parameter entities
and the large opportunity for error in constructing parameter entity declarations
and references, the issues with XSD go deeper, relating to XSD's class model and restrictions
on how groups may be redefined through the XSD redefine facility. In addition, the
XSD 1.0 redefine facility is ambiguously specified such that conforming XSD processors
may use either of two incompatible interpretations of how redefine should work. However
DITA's use of XSD depends on the interpretation as implemented by the Xerces Java
and C XSD parsers, making the use of XSD for DITA problematic in the general case.
While the XSD 1.1 override facility appears to address the issues with redefine, until
XSD 1.1 is implemented widely it cannot be mandated by the DITA standard.
Finally, the DITA Technical Committee, along with any other provider of DITA vocabularies,
constraints, and document type shells faces the practical problem of maintaining both
DTD and XSD versions of their vocabulary, which is challenging at best. An ideal solution
would allow generation of either or both of the DTD and XSD versions from a single
source. Through DITA version 1.2 the Technical Committee considered this too difficult
to attempt from either the DTD or XSD as the authoritative source.
RELAX NG offers solutions to all these challenges by providing an XML-based syntax
for document grammars that is a close equivalent to DTD syntax (avoiding the verbosity
and conceptual overhead of XSD) while making the creation of document type shells
much simpler, reducing them to essentially a simple inclusion list of modules. Because
RELAX NG patterns may unilaterally augment other patterns, RELAX NG vocabulary and
constraint modules become "self integrating", such that in most cases no additional
work is required beyond simply creating a reference to the module from the document
type shell.
Likewise, the relative simplicity of RELAX NG syntax coupled with an XML format make
it practical to generate both DTD and XSD versions of the vocabulary from the RELAX
NG.
DITA Modular Vocabulary Requirements
A DITA vocabulary module defines either a set of element types or a single global
attribute. The grammar definition for a module must satisfy the following requirements:
-
Provide the @domains attribute contribution for the module.
-
Define content models with appropriate parameterization so that the following types
of modifications may be made through the redefinition, extension, or override of those
parameters:
-
Define attribute lists with appropriate parameterization so that the following types
of modifications may be made through the redefinition, extension, or override of those
parameters:
-
Redefine the attribute list in its entirety, for example, to omit specific attributes
or set specific default values for specific attributes.
-
Extend the attribute list with global attributes defined in separate attribute domain
modules.
-
Provide common reusable content model fragments used to construct element-type-specific
content models
Constraint modules use the parameterization facilities defined in modules to constrain
element types. Thus any grammar facility must provide a way to include separate modules
that can redefine or override parameters provided by modules.
Document type shells include ("integrate") the vocabulary and constraint modules in
order to define a working document type. The document type shell must set the value
of the @domains attribute as specified on the root element of the DITA document the
document type shell governs.
Challenges Posed by DTD Syntax
As in all standard XML vocabularies intended for general use, the DITA DTDs make heavy
use of parameter entities in order to enable configuration and constraint of vocabulary.
The DITA DTD coding requirements specify the structure and naming rules for the parameter
entities used to construct DITA element type and attribute list declarations.
The most important parameters are:
-
Element type name parameter entities for use in content models. For each element type
defined in a vocabulary module there is a correponding parameter entity that expands
to the element type name. These parameter entities are used in content models, e.g.:
<!ENTITY % ph "ph" >
...
<!ENTITY % basic.ph
"%boolean; |
%cite; |
%keyword; |
%ph; |
%q; |
%term; |
%tm; |
%xref; |
%state;
"
>
-
"Domain integration" parameter entities, which are defined in domain modules and are
used to override and extend the base values of element type name parameter entities
in order to allow any specialization of the base type wherever the base type is allowed:
<!ENTITY % hi-d-ph
"b |
i |
sup |
sub |
tt |
u
"
>
Each element domain module is represented by a pair of files, one named *.ent, the
other named *.mod. The domain integration parameter entity is defined in the .ent
file while the element-type-name parameter entities are defined in the .mod files.
This use of two files for each module leads to one common error in constructing DTD
document type shells: inclusion of the wrong file, leading to confusing and difficult-to-detect
or understand errors.
-
Content model parameter entities, which define the content models for each element
type. These parameter entities are always named "tagname.content". These parameter entities allow any element type to be constrained through
separate constraint modules that override the base definition of the element's content
model parameter entity, e.g.:
<!ENTITY % body.content
"(%body.cnt; |
%bodydiv; |
%example; |
%section;)*"
>
As for all XML DTDs that make heavy use of parameter entities, one practical challenge
is working out what the effective value of any given parameter entity is, as few,
if any, DTD editing tools provide convenient ways to visualize expanded content models
or follow references back to declarations.
Another practical problem is determining which declaration of a given parameter entity
is the effective one when there are multiple declarations in multiple files. Error
messages resulting from incorrect declarations are usually not very helpful in finding
the actual cause of the error as the errors tend to be about incorrect content models
resulting from the failure to resolve a particular entity or an error in the declaration
of a redefinition of an existing entity. All complex, heavily-parameterized document
types suffer from this problem and DITA's are as complicated as any. If DITA has an
advantage in this area it is only that its coding patterns are both consistent and
mandated by the standard, making it slightly easier to detect typing errors.
DTD-syntax document type shells in DITA require multiple external parameter entity
references, in specific orders, for each structural and domain module as well as declaration
of the domain integration parameter entities, again in the right order, as well as
inclusion of any constraint modules used in the shell.
The need for multiple external parameter entities for each module adds complexity
and opportunities for error. For example, it is easy to accidentally include the wrong
file, for example, including a .mod file instead of the required .ent file. This type
of error can be hard to find because it doesn't necessarily make the resulting DTD
invalid but may make it incorrect because the order of parameter entity declarations
is not correct, causing subsequent redefinitions to have no effect.
Likewise, it is easy to make typos in the domain entity integration parameter entity
declarations, for example, omitting a "|" separator or simply misspelling the name
of a domain-defined parameter entity. Or simply forgetting to include a reference
to domain's integration parameter entity. None of these errors is easy to check programmatically
and none are reported in a way that makes the real error obvious. Even experienced
DITA DTD authors can find it difficult to diagnose and resolve these types of errors.
While the DITA standard defines and documents the coding pattern for document type
shells such that anyone should be able to simply follow the pattern in order to successfully
create their own custom shell, in practice few people even attempt it and fewer succeed
because of the inherent challenges of DTD syntax.
Challenges Posed by XML Schema
The XML Schema Document (XSD) facility presents several challenges for use with DITA
vocabularies:
-
The requirement to use the XSD redefine facility
-
Limits on redefine and the resulting need for intermediate groups and, in some cases,
intermediate files
-
Declarations for integrating domain-provided element types into base content models
-
The verbosity of the markup generally stemming from the XSD class and element type
distinction, which does not correspond to DITA's class concept.
XSD Redefine Facility
The XSD redefine facility is defined ambiguously in the XSD recommendation such that
conforming XSD processors may use either of two incompatible interpretations of redefinition,
only one of which works for DITA. This means only some XSD processors can be used
to validate XSD-based DITA documents. Fortunately, two of those processors are the
Xerces Java and C-language XSD processors, making the required XSD processing available
in all Java environments and many non-Java environments. In XSD 1.1 the Redefine facility
is deprecated:
4.2.4 Including modified component definitions (<redefine>)
Note: The redefinition feature described in the remainder of this section is ·deprecated·
and may be removed from future versions of this specification. Schema authors are
encouraged to avoid its use in cases where interoperability or compatibility with
later versions of this specification are important.
The primary issue appears to be with systems that cache schemas. If two documents
use two different top-level schemas, each of which redefines the same base model from
a third schema, it is possible that a system may cache the redefine as defined by
the first top-level schema and use it when processing against the second top-level
schema. Any system that does this will reliably fail with typical DITA documents where
there is a mix of topic types, each of which necessarily provides different redefines
for the same base models. It is not clear if any XSD processors actually have this
caching behavior.
The XSD 1.1 override facility, which was driven in part by DITA requirements, appears
to provide the override semantics DITA requires, but as XSD 1.1 is not universally
implemented it is difficult to justify requiring the use of XSD 1.1. However, because
the DITA XSDs are generated starting with DITA 1.3, it would be possible to generate
XSDs that use override in place of redefine if the DITA community requires them. As
of May 2014 it appears that the only XSD 1.1 implementations are Xerces-J and Saxon
EE, which is not sufficient to support the full DITA community.
The challenge presented by the XSD Redefine facility is its "particle preservation"
requirement, defined as follows:
The definitions within the <redefine> element itself are restricted to be redefinitions
of components from the <redefine>d schema document, in terms of themselves. That is,
-
Type definitions must use themselves as their base type definition;
-
Attribute group definitions and model group definitions must be supersets or subsets
of their original definitions, either by including exactly one reference to themselves
or by containing only (possibly restricted) components which appear in a corresponding
way in their <redefine>d selves.
This means that any redefinition of a model must reflect each of the particles in
the original model. For choice groups this is not a problem: any choice group is a
valid restriction, including an empty group. But for sequence groups it is a serious
problem, in that you cannot simply omit items from the sequence as part of the redefinition.
For example, given this base schema:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
xmlns:s1="urn:example.com:schema-01"
targetNamespace="urn:example.com:schema-01"
>
<xs:complexType name="root.type">
<xs:sequence>
<xs:element ref="s1:A"/>
<xs:element ref="s1:B"/>
<xs:element ref="s1:C"/>
</xs:sequence>
</xs:complexType>
<xs:element name="root" type="s1:root.type">
</xs:element>
<xs:element name="A" >
</xs:element>
<xs:element name="B" >
</xs:element>
<xs:element name="C" >
</xs:element>
</xs:schema>
This redefinition is invalid:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
xmlns:s1="urn:example.com:schema-01"
targetNamespace="urn:example.com:schema-01"
>
<!-- Redefine of redefined schema 01 -->
<xs:redefine schemaLocation="redefined-schema-01.xsd">
<xs:complexType name="root.type">
<xs:complexContent>
<xs:restriction base="s1:root.type">
<xs:sequence>
<xs:element ref="s1:A"/>
<xs:element ref="s1:C"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
</xs:schema>
Because the "B" particle from the origin sequence is not accounted for in the redefined
sequence.
Likewise, this attempt to make "B" disallowed is also invalid:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
xmlns:s1="urn:example.com:schema-01"
targetNamespace="urn:example.com:schema-01"
>
<!-- Redefine of redefined schema 01 -->
<xs:redefine schemaLocation="redefined-schema-01.xsd">
<xs:complexType name="root.type">
<xs:complexContent>
<xs:restriction base="s1:root.type">
<xs:sequence>
<xs:element ref="s1:A"/>
<xs:element ref="s1:B" maxOccurs="0" minOccurs="0"/>
<xs:element ref="s1:C"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
</xs:schema>
In both cases, the Xerces J parser reports that there is not a complete functional
mapping between the particles in the original model and the redefined model.
The solution is to refactor the sequence into a sequence of named groups. This allows
the groups to be referenced from a redefinition, satisfying the requirement that a
redefinition must include the thing being redefined:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
xmlns:s1="urn:example.com:schema-01" targetNamespace="urn:example.com:schema-01">
<xs:group name="A.grp">
<xs:sequence>
<xs:choice>
<xs:element ref="s1:A"/>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="B.grp">
<xs:sequence>
<xs:choice>
<xs:element ref="s1:B"/>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="C.grp">
<xs:sequence>
<xs:choice>
<xs:element ref="s1:C"/>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:complexType name="root.type">
<xs:sequence>
<xs:group ref="s1:A.grp"/>
<xs:group ref="s1:B.grp"/>
<xs:group ref="s1:C.grp"/>
</xs:sequence>
</xs:complexType>
<xs:element name="root" type="s1:root.type"> </xs:element>
<xs:element name="A"> </xs:element>
<xs:element name="B"> </xs:element>
<xs:element name="C"> </xs:element>
</xs:schema>
Note that the pattern of xs:sequence/xs:choice is required in order to control occurrence
of the choice (e.g., to make the choice optional or repeatable).
The redefinition can then look like this:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
xmlns:s1="urn:example.com:schema-01"
targetNamespace="urn:example.com:schema-01"
>
<!-- Redefine of redefined schema 01 -->
<xs:redefine schemaLocation="redefined-schema-02.xsd">
<xs:group name="B.grp">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="0">
<xs:group ref="s1:B.grp"/>
</xs:choice>
</xs:sequence>
</xs:group>
</xs:redefine>
</xs:schema>
In this case, making the "B" element effectively disallowed while maintaining the
required particle-to-particle association.
This need for additional named groups for sequences within content models makes translating
content models as normally formulated in DTD or RELAX NG grammars into XSD tedious
at best and challenging at worst. It is not clear if there is a general algorithm
for translating arbitrary content models with sequences into the necessary XSD groups
in order to then enable arbitrary constraint via redefinition. In the case of the
DITA XSDs, at least through DITA 1.2, this type of group refactoring has been done
only as needed to support constraints defined by the DITA Technical Committee. This
means that there are many element types that cannot be constrained using the XSD modules
as provided by the DITA Technical Committee. This issue is explored in more detail
below.
DITA 1.2 Group Design and XSD
In DITA every base element type may be extended through the creation of "domain" element
specializations such that anywhere the base element type is allowed the domain-defined
specializations are also allowed.
This is implemented in all grammar languages by defining the base content models using
references to some type of parameter that initially resolves to just the base element
type but that may be redefined to expand to the base type and its domain-provided
specializations. Document type shells may also omit the base type or any specialized
type, effectively imposing a constraint on the base element type as part of the domain
integration. For example, given a domain that specializes the general inline element
type <ph>, you might allow only the specialized types and omit <ph>. The naming pattern
used in all grammar languages gives the parameter the same name as the element type,
e.g., "%ph" in DTDs, <define name="ph"> in RELAX NG, and <xs:group name="ph"> in XSD.
For XSD this pattern means that there is one element-type-specific group for each
element type defined in each vocabulary module. The base definition of each group
simply allows the corresponding element:
<xs:group name="author">
<xs:sequence>
<xs:choice>
<xs:element ref="author"/>
</xs:choice>
</xs:sequence>
</xs:group>
For example, a domain could extend the <author> element by defining two specializations
of <author>, say <editor> and <primary-author>. Within document type shell XSD documents
that integrate this domain the "author" group is redefined like so:
<xs:redefine schemaLocation="urn:oasis:names:tc:dita:xsd:metaDeclGrp.xsd">
<xs:group name="author">
<xs:choice>
<xs:group ref="author"/>
<xs:group ref="jrnlmeta-d-author" />
</xs:choice>
</xs:group>
</xs:redefine>
The group "jrnlmeta-d-author" is defined like so:
<xs:group name="jrnlmeta-d-author">
<xs:choice>
<xs:element ref="editor" />
<xs:element ref="primary-author" />
</xs:choice>
</xs:group>
This redefinition satisfies the particle preservation requirement of the redefine
feature because the original particle "author" is maintained with additional new particles
added within a choice group.
Note that each element-type-specific group must itself require its contained choice
group. If this were not the case it would be impossible to define content models that
required elements. Thus the element-type-specific groups themselves cannot be used
to work around the redefinition particle preservation requirement.
Working Around Redefine Limitations: Indirection in Sequence Groups
XSD redefinition is applied at the group level such that every particle in the original
group must be represented in the redefined group. When the group defines a sequence
it is not possible to redefine the sequence in order to omit tokens.
For example, the DITA <prolog> element uses this sequence group as its abstract content
model:
(author*,
source?,
publisher?,
copyright*,
critdates?,
permissions?,
metadata*,
resourceid*,
(data.elements.incl |
foreign.unknown.incl)*)
Each element is optional. Per the rule for DITA constraints you can omit any optional
element. This means that any restriction of the content model that omits one or more
particles is a conforming constraint.
If the XSD implementation of the content model is defined as a single group the resulting
group is will not allow constraints that omit optional types:
<xs:sequence>
<xs:group ref="author" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="source" minOccurs="0"/>
<xs:group ref="publisher" minOccurs="0"/>
<xs:group ref="copyright" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="critdates" minOccurs="0"/>
<xs:group ref="permissions" minOccurs="0"/>
<xs:group ref="metadata" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="resourceid" minOccurs="0" maxOccurs="unbounded"/>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:group ref="data.elements.incl"/>
<xs:group ref="foreign.unknown.incl"/>
</xs:choice>
</xs:sequence>
The general solution is to add another layer of grouping such that for each contiguous
sequence of omittable elements there is a group whose content is an emptiable choice
or sequence.
For example, the base content model for the DITA <taskbody> element is:
((prereq |
context |
section)*,
(steps |
steps-unordered |
steps-informal)?,
result?,
example*,
postreq*)
The DITA standard defines a constraint on this content model, the "strict task" constraint,
which omits the <section> and <steps-informal> elements.
If the XSD implementation of this content model were simply the equivalent sequence
group, it would not be constrainable because the particle preservation rule does not
allow omission of the <section> or <steps-informal> groups.
One solution is to insert three groups: one for the elements before <steps>, one for
the <steps> optional choice group, and one for the elements after <steps>:
<xs:group name="taskbody.content">
<xs:sequence>
<xs:group ref="taskPreStep"/>
<xs:group ref="taskStep"/>
<xs:group ref="taskPostStep"/>
</xs:sequence>
</xs:group>
<xs:group name="taskPreStep">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:group ref="context" minOccurs="0"/>
<xs:group ref="prereq" minOccurs="0"/>
<xs:group ref="section" minOccurs="0"/>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="taskPostStep">
<xs:sequence>
<xs:group ref="result" minOccurs="0"/>
<xs:group ref="example" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="postreq" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:group>
<xs:group name="taskStep">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="1">
<xs:group ref="steps" />
<xs:group ref="steps-unordered" />
<xs:group ref="steps-informal" />
</xs:choice>
</xs:sequence>
</xs:group>
This extra level of grouping enables the constraint for <taskbody>. However, no other
sequence group content model in the DITA 1.2 XSD schemas provides a comparable set
of emptiable groups, meaning that more than 150 element types in the DITA 1.2 base
vocabulary are not constrainable without first modifying the OASIS-provided XSDs,
which violates the basic DITA principle that all copies of a given vocabulary module
are identical.
This presents an implementation challenge for the XSD generation process: is there
a general algorithm that will generate constrainable model groups that allow any valid
constraint (in particular, allowing removal of optional elements?
Declarations for Integrating Domain Element Types in XSD Document Type Shells
Domain-provided specialized element types are integrated through redefinitions specified
in document type shells. The markup itself is not particularly complicated, but it
must be specified in every document type shell that integrates a given domain. Domain-provided
elements types are "mix-in" elements, meaning that the domain-provided elements must
be allowed wherever the element they specialize is allowed. Conceptually this is equivalent
to an XSD substitution group. However, it appears that XSD substitution groups do
not work reliably for this and thus are not used by the DITA XSDs.
Because the integration of each domain requires explicit redefinition in the XSD document
type shell, XSD domains are not self integrating.
The names of the groups to be referenced in the redefined groups are determined by
the short name of each integrated domain. The DITA XSD coding requirements specify
that the domain integration groups must be named such that, given the domain short
name, you can reliably construct the domain integration group name.
A typical document type shell is the OASIS-provided concept topic type shell:
<xs:redefine schemaLocation="urn:oasis:names:tc:dita:xsd:commonElementGrp.xsd:1.2">
<xs:group name="keyword">
<xs:choice>
<xs:group ref="keyword"/>
<xs:group ref="pr-d-keyword" />
<xs:group ref="ui-d-keyword" />
<xs:group ref="sw-d-keyword" />
</xs:choice>
</xs:group>
<xs:group name="ph">
<xs:choice>
<xs:group ref="ph"/>
<xs:group ref="pr-d-ph" />
<xs:group ref="ui-d-ph" />
<xs:group ref="hi-d-ph" />
<xs:group ref="sw-d-ph" />
</xs:choice>
</xs:group>
<xs:group name="pre">
<xs:choice>
<xs:group ref="pre"/>
<xs:group ref="pr-d-pre" />
<xs:group ref="ui-d-pre" />
<xs:group ref="sw-d-pre" />
</xs:choice>
</xs:group>
<xs:group name="dl">
<xs:choice>
<xs:group ref="dl"/>
<xs:group ref="pr-d-dl"/>
</xs:choice >
</xs:group >
<xs:group name="fig">
<xs:choice>
<xs:group ref="fig"/>
<xs:group ref="pr-d-fig"/>
<xs:group ref="ut-d-fig" />
</xs:choice>
</xs:group >
<xs:group name="index-base">
<xs:choice>
<xs:group ref="index-base"/>
<xs:group ref="indexing-d-index-base"/>
</xs:choice>
</xs:group >
<xs:group name="note">
<xs:choice>
<xs:group ref="note"/>
<xs:group ref="hazard-d-note"/>
</xs:choice>
</xs:group >
<xs:group name="term">
<xs:choice>
<xs:group ref="term"/>
<xs:group ref="abbrev-d-term"/>
</xs:choice>
</xs:group >
</xs:redefine>
How RELAX NG Addresses DITA Requirements
RELAX NG provides an almost ideal match of syntax and semantics to DITA vocabulary
architecture requirements:
-
The RELAX NG pattern approach is a good match to DTD semantics and thus to DITA semantics.
-
The ability to extend patterns unilaterally makes modules self-integrating, reducing
the complexity of document type shells.
-
RELAX NG's XML syntax plus semantic match to DTDs makes generating conforming DITA
DTDs practical.
-
RELAX NG's XML syntax makes generating XSDs practical, if challenging due to requirements
for XSDs.
The use of RELAX NG for DITA does require two things not in the base RELAX NG standard:
-
Attribute default values. These are provided for by the companion RELAX NG DTD Compatibility
standard. One of us (Bina) implemented support for attribute defaults as an enhancement
to the open-source JING library, making RELAX NGs directly usable for DITA document
processing in any Java processing environment.
-
DITA-specific metadata for vocabulary and constraint modules and document type shells.
DITA-specific metadata is required in order to enable generation of DTD and XSD versions
of the RELAX NG document type shells and modules, such as the public IDs to use for
specific generated modules, the module types, and module short names, as well as DITA-specific
properties for individual element types, such as a long name and the initial DITA
versions for patterns and pattern components.
The one tedious aspect of RELAX NG that adds complexity to the DITA document type
shells is the need to have special declarations in the shell for elements that define
@id attributes of type "ID".
In DITA most elements define the @id attribute as NMTOKEN rather than as an XML ID.
However, some element types, in particular, <topic> and all specializations of <topic>,
use XML IDs. RELAX NG's rules for "any" patterns do not allow two different element
types to have different datatypes for the same attribute. DITA document type shells
must work around this by redefining the "any" patterns to explicitly exclude those
element types or foreign namespaces that define @id attributes as type ID. However,
for most shells this redefinition is the same except for the tagnames of the topic
types defined or included in the shell.
The only other component of document type shells that must be set manually is the
value of the @domains attribute for the root topic or map element defined by the shell
as RELAX NG provides no way to dynamically construct the pattern for attribute defaults.
However, each vocabulary and constraint module declares its @domains contribution
in DITA-specific metadata. The DITA Technical Committee provides a simple XQuery script
that updates the value of the @domains attribute to reflect the modules actually included,
removing the need to manually set and maintain the @domains value.
RELAX NG is a Good Match to DTDs
The RELAX NG pattern approach, as opposed to the XSD type/element approach, provides
a close semantic and syntactic match to XML DTDs, making it relatively easy for DTD
authors to transition to RELAX NG as their grammar language. There is an almost one-to-one
correspondence between DTD syntactic constructs and RELAX NG grammar components. This
makes it relatively easy to translate existing DTD-syntax vocabulary modules into
the equivalent RELAX NG grammars. It also allows the DITA-defined RELAX NG coding
requirements to be as close to the DTD coding requirements as possible, maximizing
the applicability of existing DTD coding knowledge to DITA RELAX NG grammars.
The RELAX NG compact syntax is also syntactically similar to DTD syntax. The compact
syntax is less convenient for DITA vocabularies because DITA grammars do require use
of non-RELAX NG elements and attributes but it is still usable as RELAX NG provides
ways of encoding foreign elements and attributes in the compact syntax. The DITA Technical
Committee generates RELAX NG compact syntax versions of all the TC-defined DITA vocabulary.
Modules are Self Integrating
The most dramatic advantage of RELAX NG over both DTD and XSD is the ability for one
pattern to unilaterally extend another pattern. This allows DITA domain modules to
automatically extend the patterns for the base elements those domains specialize.
As for DTDs and XSDs, each element type is represented by a pattern whose name is
the same as the element type:
<define name="ph">
<ref name="ph.element"/>
</define>
The domain specialization of a given element simply extends the element-type pattern
to add the specializations provided by the domain:
<define name="hi-d-ph">
<choice>
<ref name="b.element"/>
<ref name="i.element"/>
<ref name="line-through.element" dita:since="1.3"/>
<ref name="overline.element" dita:since="1.3"/>
<ref name="sup.element"/>
<ref name="sub.element"/>
<ref name="tt.element"/>
<ref name="u.element"/>
</choice>
</define>
<define name="ph" combine="choice">
<ref name="hi-d-ph"/>
</define>
The combine="choice"
on the domain-specific definition of the "ph" pattern in this example makes the effective
value of the "ph" pattern the base tokens plus all the tokens defined in the "hi-d-ph"
pattern. This corresponds directly to the domain integration parameter entities in
DTDs and domain integration redefines in XSDs, but requires no additional work in
document type shells.
The document type shell can then be a simple set of module inclusions. This eliminates
almost all of the complexity and opportunity for error of DTD and XSD document type
shells. In short, it makes creating DITA document type shells about as easy as it
could possibly be.
DTD and XSD Generation
While RELAX NG has many advantages for DITA vocabulary authors the DITA community
still requires DTDs and, to a lesser extent, XSDs. Almost all DITA-aware tools are
DTD-aware and a few are XSD-only. Few support use of RELAX NG today. Thus the DITA
Technical Committee must continue to provide DTD and XSD versions of all TC-defined
vocabulary. In addition, these DTDs and XSDs must themselves conform to the DITA coding
requirements for DTDs.
One of us (Kimber) has implemented XSLT-based transforms to generate conforming DTD,
XSD, and RELAX NG compact syntax modules and shells from the RELAX NG XML syntax modules.
These transforms allow the DITA Technical Committee to make the RELAX NG vocabulary
the authoritative master from which all other forms are generated, significantly reducing
the cost of maintaining multiple grammar formats for the DITA vocabulary.
Conclusions and Future Work
As an alternative to DTDs, RELAX NG has proven to be superior to XSD in almost every
way. It is provides a good semantic and syntactic match to DTDs. It's rules for extending
and overriding patterns work well for DITA's specialization and constraint features.
It's XML syntax makes implementing generation of other formats practical using normal
XML tools (XSLT, XQuery). The ability to unilaterally extend patterns makes RELAX
NG document type shells about as easy as it can be. Even if used only as a source
for then generating the DTDs and XSDs used with DITA processing tools, RELAX NG offers
significant benefits to DITA document type shell and module authors.
Through this experience we have identified potential improvements to RELAX NG that
would make its use even simpler:
With these two refinements, DITA modules would be complete self-integrating, making
DITA document type shells truly just inclusion lists of modules.
The question of generation of constrainable XSD content models remain open. More thought
and experimentation is required but at the time of writing it is not clear that a
general algorithm for translating sequence groups to the necessary XSD groups is either
possible or desirable. In addition, it is not clear that there is sufficient use of
XSDs within the DITA community with non-TC-provided constraints to justify the effort
of trying to generate constrainable XSDs. One piece of evidence that this is the case
is the fact that the issue with the general lack of constrainability was not discovered
until we started implementing the XSD generation process, meaning that no DITA user
reported any issue with XSD constraints between the time DITA 1.1 was released and
now. Either nobody tried to implement constraints of sequence groups using XSDs in
that time or anyone who did simply modified their TC-provided XSD files locally and
never reported the issue to the DITA Technical Committee or to the DITA community
at large.
At the time of writing the decision of the DITA Technical Committee is to generate
the DITA 1.3 XSDs using the same content model patterns as for DITA 1.2, treating
those content models that require constraint (e.g., taskbody) as special cases within
the XSD generation transform. Because the XSDs are generated the Technical Committee
can add additional special cases as required, replace the use of Redefine with Override,
or improve the general model generation algorithm.