Namespaces and DTDs

Namespaces are completely independent of DTDs and can be used in both valid and invalid documents. A document can have a DTD but not use namespaces or use namespaces but not have a DTD. It can use both namespaces and DTDs or neither namespaces nor DTDs. Namespaces do not in any way change DTD syntax nor do they change the definition of validity. For instance, the DTD of a valid document that uses an element named dc:title must include an ELEMENT declaration properly specifying the content of the dc:title element. For example:

<!ELEMENT dc:title (#PCDATA)>

The name of the element in the document must exactly match the name of the element in the DTD, including the prefix. The DTD cannot omit the prefix and simply declare a title element. The same is true of prefixed attributes. For instance, if an element used in the document has xlink:type and xlink:href attributes, then the DTD must declare the xlink:type and xlink:href attributes, not simply type and href.

Conversely, if an element uses an xmlns attribute to set the default namespace and does not attach prefixes to elements, then the names of the elements must be declared without prefixes in the DTD. The validator neither knows nor cares about the existence of namespaces. All it sees is that some element and attribute names happen to contain colons; as far as it's concerned, such names are perfectly valid as long as they're declared.

Requiring DTDs to declare the prefixed names, instead of the raw names or some combination of local part and namespace URI, makes it difficult to change the prefix in valid documents. The problem is that changing the prefix requires changing all declarations that use that prefix in the DTD. However, with a little forethought, parameter entity references can alleviate the pain quite a bit.

The trick is to define both the namespace prefix and the colon that separates the prefix from the local name as parameter entities, like this:

<!ENTITY % dc-prefix "dc">
<!ENTITY % dc-colon ":">

The second step is to define the qualified names as more parameter entity references, like these:

<!ENTITY % dc-title       "%dc-prefix;%dc-colon;title">
<!ENTITY % dc-creator     "%dc-prefix;%dc-colon;creator">
<!ENTITY % dc-description "%dc-prefix;%dc-colon;description">
<!ENTITY % dc-date        "%dc-prefix;%dc-colon;date">

Then you use the entity references for the qualified name in all declarations, like this:

<!ELEMENT %dc-title; (#PCDATA)>
<!ELEMENT %dc-creator; (#PCDATA)>
<!ELEMENT %dc-description; (#PCDATA)>
<!ELEMENT %dc-date; (#PCDATA)>
<!ELEMENT rdf:Description
  ((%dc-title; | %dc-creator; | %dc-description; | %dc-date; )*)
>

Now a document that needs to change the prefix simply changes the parameter entity definitions. In some cases, this will be done by editing the DTD directly. In others, it may be done by overriding the definitions in the document's internal DTD subset. For example, to change the prefix from dc to dublin, you'd add this entity definition somewhere in the DTD before the normal definition:

<!ENTITY % dc-prefix "dublin">

If you wanted to use the default namespace instead of explicit prefixes, you'd redefine both the dc-prefix and dc-colon entities as the empty string, like this:

<!ENTITY % dc-prefix "">
<!ENTITY % dc-colon  "">