A. Building XHTML Relax NG Modules

Contents

This section is normative.

XHTML modules are implemented as RelaxNG fragments. When these fragments are assembled in a specific manner (described in Developing RelaxNG with defined and extended modules) is a representation of a complete document type. This representation can then be used for validation of instances of the document type.

The key to combining these fragments into a meaningful DTD is the rules used to define the fragments. This section defines those rules. When these rules are followed, DTD authors can be confident that their modules will interface cleanly with other XHTML-compatible modules.

This specification classifies parameter entities into seven categories and names them consistently using the following suffixes:

.mod
parameter entities use the suffix .mod when they are used to represent a DTD module (a collection of elements, attributes, parameter entities, etc). In this specification, each module is an atomic unit and may be represented as a separate file entity.
.module
parameter entities use the suffix .module when they are used to control the inclusion of a DTD module by containing either of the conditional section keywords INCLUDE or IGNORE.
.qname
parameter entities use the suffix .qname when they are used to represent the qualified name of an element. See Defining the Namespace of a Module for more information on qualified names.
.content
parameter entities use the suffix .content when they are used to represent the content model of an element type.
.class
parameter entities use the suffix .class when they are used to represent elements of the same class.
.mix
parameter entities use the suffix .mix when they are used to represent a collection of element types from different classes.
.attrib
parameter entities use the suffix .attrib when they are used to represent a group of tokens representing one or more complete attribute specifications within an ATTLIST declaration.

For example, in HTML 4, the %block; parameter entity is defined to represent the heterogeneous collection of element types that are block-level elements. In this specification, the corollary parameter entity is %Block.mix;.

When defining parameter entities in the classes defined here, modules should scope the names of the entities by using unique prefixes. For example, the content model for the element myelement in the module mymodule could be named MYMODULE.myelement.content. Other schemes are possible. Regardless of the scheme used, module authors should strive to ensure that parameter entities they define are named uniquely so that they do not collide with other parameter entities and so that the interface methods for the module are obvious to its users.

A.1. Defining the Namespace of a Module

XHTML requires that the elements and attributes declared in a module be within a defined XML namespace [XMLNS]. The identification of this namespace is an arbitrary URI. XHTML requires that when a module is implemented using an XML DTD, the module declares the namespace in a special manner. The purpose of this is to permit the selection, at document parse/validation time, of the use of namespace prefixes and of the prefix that is used to identify elements and attributes from the module.

Content developers who wish to develop documents based upon hybrid document types may choose to use XML namespace prefixes on elements from the XHTML namespace, on elements from other namespaces, or on both. In order to ensure that such documents are XHTML conforming and backward compatible with non-namespace aware tools, the W3C recommends that content developers do not use XML namespace prefixes on elements from the XHTML namespace. When content developers are interested in having their content processed by namespace-aware processors, the W3C further recommends that elements in non-XHTML namespaces be specified using an XML namespace prefix rather than relying upon XML namespace defaulting mechanisms.

Each XHTML-conforming module implemented as an XML DTD is required to define a default XML namespace prefix, a method for changing this prefix within a document instance, and a marked section that turns on the processing of the prefix.

Note that it is legal and expected for multiple modules to be part of the same namespace when they are related. All of the XHTML modules, for example, are part of the same namespace.

A.1.1. Qualified Names sub-module

First, you need to define a qualified names sub-module (a sub-module is just a file entity that is separated so that it can be incorporated into the ultimate DTD at the appropriate point). The qualified names sub-module is built using the following steps (where the string MODULE is replaced with an appropriate string for the new module):

  1. Define a parameter entity MODULE.prefixed that announces whether the elements in the module are being used with XML namespace prefixed names or not. This parameter entity's default value should be "%NS.prefixed;". The NS.prefixed parameter entity is defined by the XHTML framework to be IGNORE by default, and can be used in a document instance to switch on prefixing for all included namespaces (including that of the XHTML modules).
  2. Define a parameter entity MODULE.xmlns that contains the namespace identifier for this module.
  3. Define a parameter entity MODULE.prefix that contains the default prefix string to use when prefixing is enabled.
  4. Define a parameter entity MODULE.pfx that is "%MODULE.prefix;:" when prefixing is enabled, and "" when it is not.
  5. Define a parameter entity MODULE.xmlns.extra.attrib that contains the declaration of any XML namespace attributes for namespaces referenced by this module (e.g., xmlns:xlink). When %MODULE.prefixed is set to INCLUDE, this attribute should include the xmlns:%MODULE.prefix; declaration as well.
  6. Define a parameter entity XHTML.xmlns.extra.attrib as MODULE.xmlns.extra.attrib. This is usually overridden by the document type's driver file, but if not this definition will take over as the default.
  7. For each of the elements defined by the module, create a parameter entity of the form "MODULE.NAME.qname" to hold its qualified name. The value for this parameter entity must be "%MODULE.pfx;NAME". In this way, the parsed value will be "PREFIX:NAME" when prefixes are enabled, and "NAME" otherwise.

    If the module adds attributes to elements defined in modules that do not share the namespace of this module, declare those attributes so that they use the %MODULE.pfx prefix. For example:

    <ENTITY % MODULE.img.myattr.qname "%MODULE.pfx;myattr" >
    

An example of a qname sub-module for a hypothetical Inventory Module is included below:

<!-- ...................................................................... -->
<!-- Inventory Qname Module ................................................... -->
<!-- file: inventory-qname-1.mod
	 PUBLIC "-//MY COMPANY//ELEMENTS XHTML Inventory Qnames 1.0//EN"
	 SYSTEM "http://www.example.com/DTDs/inventory-qname-1.mod"
	 xmlns:inventory="http://www.example.com/xmlns/inventory"
     ...................................................................... -->
<!-- Declare the default value for prefixing of this module's elements -->
<!-- Note that the NS.prefixed will get overridden by the XHTML Framework or
     by a document instance. -->
<!ENTITY % NS.prefixed "IGNORE" >
<!ENTITY % Inventory.prefixed "%NS.prefixed;" >
<!-- Declare the actual namespace of this module -->
<!ENTITY % Inventory.xmlns "http://www.example.com/xmlns/inventory" >
<!-- Declare the default prefix for this module -->
<!ENTITY % Inventory.prefix "inventory" >
<!-- Declare the prefix for this module -->
<![%Inventory.prefixed;[
<!ENTITY % Inventory.pfx "%Inventory.prefix;:" >
]]>
<!ENTITY % Inventory.pfx "" >
<!-- Declare the xml namespace attribute for this module -->
<![%Inventory.prefixed;[
<!ENTITY % Inventory.xmlns.extra.attrib
	"xmlns:%Inventory.prefix;	%URI.datatype;	#FIXED	'%Inventory.xmlns;'" >
]]>
<!ENTITY % Inventory.xmlns.extra.attrib "" >
<!-- Declare the extra namespace that should be included in the XHTML
     elements -->
<!ENTITY % XHTML.xmlns.extra.attrib
	"%Inventory.xmlns.extra.attrib;" >
<!-- Now declare the qualified names for all of the elements in the
     module -->
<!ENTITY % Inventory.shelf.qname "%Inventory.pfx;shelf" >
<!ENTITY % Inventory.item.qname "%Inventory.pfx;item" >
<!ENTITY % Inventory.desc.qname "%Inventory.pfx;desc" >
<!ENTITY % Inventory.sku.qname "%Inventory.pfx;sku" >
<!ENTITY % Inventory.price.qname "%Inventory.pfx;price" >

A.1.2. Declaration sub-module(s)

Next, you need to define one or more "declaration sub-modules". The purpose of these file entities is to declare the XML DTD elements and attribute lists. An XHTML declaration module should be constructed using the following process:

  1. Define a parameter entity to use within the ATTLIST of each declared element. This parameter entity should contain %NS.decl.attrib; when %MODULE.prefixed; is set to INCLUDE, and %NS.decl.attrib; plus "xmlns %URI.datatype; #FIXED '%MODULE.xmlns;'" when %MODULE.prefixed; is set to IGNORE.
  2. Declare all of the elements and attributes for the module. Within each ATTLIST for an element, include the parameter entity defined above so that all of the required xmlns attributes are available on each element in the module.
  3. If the module adds attributes to elements defined in modules that do not share the namespace of this module, declare those attributes so that they use the %MODULE.pfx prefix. For example:

    <ENTITY % MODULE.img.myattr.qname "%MODULE.pfx;myattr" >
    <!ATTLIST %img.qname;
          %MODULE.img.myattr.qname;    CDATA          #IMPLIED
    >
    

    This would add an attribute to the img element of the Image Module, but the attribute's name will be the qualified name, including prefix, when prefixes are selected for a document instance. It also adds the xmlns:MODULE_PREFIX attribute to the img element's attribute list so that an XML Namespace-aware parser would know how to resolve the namespace based upon its prefix.

The following example shows a declaration sub-module for a hypothetical Inventory module.

<!-- ...................................................................... -->
<!-- Inventory Elements Module ................................................... -->
<!-- file: inventory-1.mod
	 PUBLIC "-//MY COMPANY//ELEMENTS XHTML Inventory Elements 1.0//EN"
	 SYSTEM "http://www.example.com/DTDs/inventory-1.mod"
	 xmlns:inventory="http://www.example.com/xmlns/inventory"
     ...................................................................... -->
<!-- Inventory Module
     shelf
        item
	   sku
	   desc
	   price
     This module defines a simple inventory item structure
-->
<!-- Define the global namespace attributes -->
<![%Inventory.prefixed;[
<!ENTITY % Inventory.xmlns.attrib
    "%NS.decl.attrib;"
>
]]>
<!ENTITY % Inventory.xmlns.attrib
	 "xmlns	%URI.datatype;	#FIXED '%Inventory.xmlns;'"
>
<!-- Define a common set of attributes for all module elements -->
<!ENTITY % Inventory.Common.attrib
         "%Inventory.xmlns.attrib;
	  id               ID                   #IMPLIED"
>
<!-- Define the elements and attributes of the module -->
<!ELEMENT %Inventory.shelf.qname;
     ( %Inventory.item.qname; )* >
<!ATTLIST %Inventory.shelf.qname;
     location	CDATA	#IMPLIED
     %Inventory.Common.attrib;
>
<!ELEMENT %Inventory.item.qname;
     ( %Inventory.desc.qname;, %Inventory.sku.qname;, %Inventory.price.qname;) >
<!ATTLIST %Inventory.item.qname;
     location	CDATA	#IMPLIED
     %Inventory.Common.attrib;
>
<!ELEMENT %Inventory.desc.qname; ( #PCDATA ) >
<!ATTLIST %Inventory.desc.qname;
     %Inventory.Common.attrib;
>
<!ELEMENT %Inventory.sku.qname; ( #PCDATA ) >
<!ATTLIST %Inventory.sku.qname;
     %Inventory.Common.attrib;
>
<!ELEMENT %Inventory.price.qname; ( #PCDATA ) >
<!ATTLIST %Inventory.price.qname;
     %Inventory.Common.attrib;
>
<!-- end of inventory-1.mod -->

A.1.3. Using the module as a stand-alone DTD

It is sometimes desirable to have an XHTML module also usable as a stand alone DTD. A good example of this is our Inventory module above. These items need to be embeddable in an XHTML document, and also need to be available as free-standing documents extracted from a database (for example). The easiest way to accomplish this is to define a DTD file that instantiates the components of your module. Such a DTD would have this structure:

  1. Include the XHTML Datatypes Module (your qnames module likely uses some of these datatypes - it certainly uses the URI datatype for the xmlns attribute).
  2. Include the Qnames Module for your module.
  3. Define the parameter entity NS.decl.attrib to be %MODULE.xmlns.extra.attrib;.
  4. Include the Declaration Module(s) for your module.

An example of this for our Inventory module is included below:

<!-- ...................................................................... -->
<!-- Inventory Elements DTD ............................................... -->
<!-- file: inventory-1.dtd
	 PUBLIC "-//MY COMPANY//DTD XHTML Inventory 1.0//EN"
	 SYSTEM "http://www.example.com/DTDs/inventory-1.dtd"
	 xmlns:inventory="http://www.example.com/xmlns/inventory"
     ...................................................................... -->
<!-- Inventory Module
     shelf
        item
	   sku
	   desc
	   price
     This module defines a simple inventory item structure
-->
<!-- Bring in the datatypes -->
<!ENTITY % xhtml-datatypes.mod
         PUBLIC "-//W3C//ENTITIES XHTML Datatypes 1.0//EN"
		 "http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-datatypes-1.mod" >
%xhtml-datatypes.mod;
<!-- Bring in the qualified names -->
<!ENTITY % Inventory-qname.mod SYSTEM "inventory-qname-1.mod" >
%Inventory-qname.mod;
<!ENTITY % NS.decl.attrib "%Inventory.xmlns.extra.attrib;">
<!ENTITY % Inventory.mod SYSTEM "inventory-1.mod" >
%Inventory.mod;
<!-- end of inventory-1.dtd -->

This DTD can then be referenced by documents that use only the elements from your module:

<!DOCTYPE shelf SYSTEM "inventory-1.dtd">
<shelf xmlns="http://www.example.com/xmlns/inventory">
    <item>
        <desc>
	  this is a description.
	</desc>
        <sku>
	  this is the price.
        </sku>
        <price>
	  this is the price.
	</price>
    </item>
</shelf>

This method permits the definition of elements and attributes that are scoped within their own namespace. It also permits content developers to use the default prefix for the elements and attributes:

<!DOCTYPE inventory:shelf SYSTEM "inventory-1.dtd" [
	<!ENTITY % Inventory.prefixed "INCLUDE">
]>
<inventory:shelf xmlns:inventory="http://www.example.com/xmlns/inventory">
    <inventory:item>
        <inventory:desc>
          this is a description.
        </inventory:desc>
        <inventory:sku>
          this is the sku.
        </inventory:sku>
        <inventory:price>
          this is the price.
        </inventory:price>
    </inventory:item>
</inventory:shelf>

Finally, a document instance can use a different XML namespace prefix by redeclaring it in the DOCTYPE header and its internal subset:

<!DOCTYPE i:shelf SYSTEM "inventory-1.dtd" [
	<!ENTITY % Inventory.prefixed "INCLUDE">
	<!ENTITY % Inventory.prefix "i">
]>
<i:shelf xmlns:i="http://www.example.com/xmlns/inventory">
    <i:item>
        <i:desc>
          this is a description.
        </i:desc>
        <i:sku>
          this is the price.
        </i:sku>
        <i:price>
          this is the price.
        </i:price>
    </i:item>
</i:shelf>

A.1.4. Namespace Idiosyncrasies

While the approach defined here permits the definition of markup languages that are XML and XML namespaces conforming, some behaviors defined by the XML namespaces specification are not supported:

  1. XML namespaces permit the redeclaration of the xmlns attribute for a namespace at any point in the tree. It further permits this redeclaration to switch between namespace defaulting and prefixed usage, and permits the changing of the prefix. The method defined in this document does not permit this. Throughout a document instance a given namespace must continue to use the same namespace prefix (when prefixing is used), or must continue to be used in the default scope.

  2. When using XML namespace defaulting, it is legal to rely upon the DTD of the document to inform parsers of the namespace of elements. However, since namespace aware processors are not required to include the DTD when evaluating a document, content developers should declare the XML namespace of an element whenever the namespace changes:

    ...
    <p>
       <myelement xmlns="..." />
    </p>