3.1. Document Type Definition (DTD)

A DTD is a notation to define elements that are allowed to appear in an XML file as well as the type of information they can contain. Table 3.1 gives an overview of some of the more frequent definitions of elements, attributes and entity that can be made in a DTD. These definitions are pseudo-XML tags in the sense that they look like XML start-tags without their corresponding end-tags. For mainly historical reasons, DTDs are not well-formed XML files. The types for DTDs are most often given as either:

Table 3.1. DTD syntax reminder

<!DOCTYPE rootElement SYSTEM «"»file name«"» «>» {[ !ENTITY *]}? «>»
<!ELEMENT NCName «(» {#PCDATA «|» }? regexpOf element name «)» «>»
<!ELEMENT NCName (#PCDATA) «>»
<!ELEMENT NCName EMPTY «>»
<!ATTLIST elementNCName attributeNCName declValue default «>» 
      declValue = CDATA | ID | IDREF | «(» CNAME+ «)» 
      default = {#REQUIRED | #IMPLIED}
<![CDATA[ ... ]]«>»
<!ENTITY name «"» ... «"» «>»
<!ENTITY % name «"» ... «"» «>»
<!ENTITY name SYSTEM «"»file name«"» «>» 

A reminder of the subset of the DTD syntax used in Example 3.1 and Example 3.2. CDATA is character data as is, but PCDATA is parsed character data that can contain references to entities. Names in italics refer to other elements. declValue and default are not part of the DTD syntax, they are only handy abbreviations in this table. Regular expressions syntax is given in Table B.1. Terminal identifiers are indicated in bold and terminal symbols are enclosed in «chevrons».


Example 3.1 is a validating DTD for the XML instance document given in Example 2.2. Elements are defined with an !ELEMENT tag, see wine (line 5‑2 of Example 3.1), containing a regular expression indicating constraints on its children elements: it is an element with up to four children elements in sequence: purchaseDate, quantity, rating and comment, the last two being optional. purchaseDate (line 6‑3) can contain character data and no other elements. A cellar (line 3‑1) is a list (possibly empty) of wine elements. A name (line 12‑6) is a non-empty list of either a first, initial or family in any order; as the order of these elements is not fixed within a name element, we must allow an infinite repetition of these without guaranteeing that the same element is not given . This illustrates some of the limitations on the types of constraints that can be easily represented with a DTD. The alternative would be to give explicitly all permutations of the three elements within a name.

Attributes are defined using !ATTLIST tags indicating the element to which they belong, their name, their type and whether they are mandatory (#REQUIRED) or optional (#IMPLIED). See for example the !ATTLIST for the code attribute of the wine element (line 10‑5).

A DTD can also contain definitions of entities that act as text macros that are replaced textually either in the instance document or in the DTD itself. Entities whose definitions start with <!ENTITY such as guy (already illustrated in Example 2.2) define textual replacements where they are called, i.e. where they appear between & and ;. There are five predefined entities :

&lt;

a less-than sign (<) in an XML file because < is reserved to indicate the start of a tag;

&amp;

As we have introduced the ampersand to indicate the start of an entity, we need a way to insert an ampersand (&);

&quot;

for inserting a ";

&apos;

for inserting a ' ;

&gt;

by symmetry with &lt; even though it is not strictly needed.

Entities are replaced in an XML file when the file is first read in memory before its interpretation; that means that those entities are replaced within any context even within strings.

Entity replacements can also be used within the DTDs themselves to modularize them. These types of entities are called parameter entities and they are distinguished from ordinary entities by adding a percent sign preceding the name of the parameter entity and its definition, see address (see line 26‑9). Its call is preceded by a percent sign instead of an ampersand see owner (line 32‑10) and location (line 33‑11). Another special kind of entity, introduced by SYSTEM, refers to a file such as wine-catalog (line 36‑12). This entity can then be used to include a file as is shown on the last line of the cellar DTD Example 3.1 which includes the wine catalog DTD Example 3.2. As the parameter and system entities are replaced when the DTD is built, they cannot be used in instance documents so no entity is needed to enter a percent.

Example 3.1. [CellarBook.dtd] DTD for the cellar book, validation of the instance file in Example 2.2

ELEMENTs and ATTLISTs are independent, indentation is ignored by the DTD processor, it is used here for the human reader only, to highlight some inclusion dependencies.

  1 <?xml version="1.0" encoding="UTF-8"?>
    
    <!ELEMENT cellar (wine)* >                                           (1)
    
  5 <!ELEMENT wine (purchaseDate,quantity,rating?,comment?) >            (2)
        <!ELEMENT purchaseDate (#PCDATA) >                               (3)
        <!ELEMENT quantity (#PCDATA) >                                   (4)
        <!ELEMENT rating EMPTY >
            <!ATTLIST rating stars CDATA #IMPLIED>
 10     <!ATTLIST wine code IDREF #REQUIRED >                            (5)
    
    <!ELEMENT name (first | family | initial)+ >                         (6)
        <!ELEMENT first (#PCDATA) >
        <!ELEMENT family (#PCDATA) >
 15     <!ELEMENT initial (#PCDATA) >
        
    <!ELEMENT cellar-book (wine-catalog, owner, location, cellar) >      (7)
    
    <!-- [general] entities for use in instance document -->
 20 <!ENTITY guy "Guy Lapalme" >                                         (8)
    <!ENTITY eacute "&#xe9;" >
    <!ENTITY mtl "Montr&eacute;al" >
    <!ENTITY GL "&guy;, &mtl;" >
    
 25 <!-- parameter entities for use within a DTD -->
    <!ENTITY % address "(street, city, province, postal-code)" >         (9)
        <!ELEMENT street (#PCDATA) >
        <!ELEMENT city (#PCDATA) >
        <!ELEMENT province (#PCDATA) >
 30     <!ELEMENT postal-code (#PCDATA) >
    
    <!ELEMENT owner (name,%address;) >                                   (10)
    <!ELEMENT location %address; >                                       (11)
    
 35 <!-- system entity for including a file -->
    <!ENTITY  % wine-catalog SYSTEM "WineCatalog.dtd" >                  (12)
    %wine-catalog;
    

1

A cellar is a possibly empty list of wines.

2

A wine is defined by a purchase date, a quantity, an optional rating and an optional comment.

3

The purchase date is a string.

4

A quantity is also a string.

5

A code must refer to an id defined in the wine catalog.

6

The name is a non-empty list consisting of a first name, a family name and an initial; this somewhat loose definition of a name illustrates some of the limitations of the the regular expression mechanism in the DTD.

7

The cellar book is composed of the wine catalog, the owner, the location, and the cellar itself.

8

Some definitions of entities and how they can be composed.

9

Parameter entities can be used in the definition of other entities.

10

Use of a parameterized entity defined on line 26‑9.

11

Another use of the same parameterized entity.

12

A parameterized entity definition for file inclusion; here it is used in the following line to include the DTD definitions in the wine catalog.


We now look at the validation of the wine catalog (Example 3.2). Given the fact that all element names must be unique in a DTD (there are no namespaces in DTDs), we must give a different name to the wine element of Example 3.1. Here we decided to call it cat-wine (line 4‑1). The attribute format (line 10‑2) shows an example of an enumeration of values from which the attribute value must necessarily be chosen. The link between the wine and the cat-wine elements is made using the code (line 13‑3 of Example 3.2) of type ID and its reference in line 10‑5 of Example 3.1 which is of type IDREF. In an XML file, all values of type ID must be distinct and values of type IDREF must refer to an existing ID.

Example 3.2. [WineCatalog.dtd] DTD to validate the wine catalog, included in Example 3.1

  1 <?xml version="1.0" encoding="UTF-8"?>
    <!ELEMENT wine-catalog (cat-wine*) >
    
    <!ELEMENT cat-wine (properties, origin,                              (1)
  5                     (tasting-note?,food-pairing?,comment?)*,
                        price,year) >
        <!ATTLIST cat-wine name CDATA #REQUIRED >
        <!ATTLIST cat-wine appellation CDATA #IMPLIED >
        <!ATTLIST cat-wine classification CDATA #IMPLIED >
 10     <!ATTLIST cat-wine format (375ml | 750ml | 1l | magnum           (2)
                           | jeroboam | rehoboam | mathusalem | salmanazar 
                           | balthazar | nabuchodonosor) #REQUIRED >
        <!ATTLIST cat-wine code ID #REQUIRED>                            (3)
        <!ELEMENT properties (color,alcoholic-strength,nature?) >
 15         <!ELEMENT color (#PCDATA) >
            <!ELEMENT alcoholic-strength (#PCDATA) >
            <!ELEMENT nature (#PCDATA) >
        <!ELEMENT origin (country,region,producer) >
            <!ELEMENT country (#PCDATA) >
 20         <!ELEMENT region (#PCDATA) >
            <!ELEMENT producer (#PCDATA) >
            
        <!ENTITY % Comment "(#PCDATA | emph | bold)*" >
        <!ELEMENT emph (#PCDATA) >
 25     <!ELEMENT bold (#PCDATA) >
        
        <!ELEMENT comment %Comment; >
        <!ELEMENT tasting-note %Comment; >
        <!ELEMENT food-pairing %Comment; >
 30     
        <!ELEMENT price (#PCDATA) >
        <!ELEMENT year (#PCDATA) >
        

1

A wine entry in the catalog is a list of properties, then the wine origins, followed by an optional list of tasting-notes, food-pairing suggestions and comment; finally the price and year have to be given.

2

The format is given as a list of literal values from which the actual value of the attribute must be chosen.

3

The unique code for the wine that must bet matched by a reference at line 10‑5 of Example 3.1


3.1.1. Associating an Instance File with a DTD

The link between a DTD and an XML file that it validates can be done externally using an XML Editor or by a command line argument to a validation program. But most DTD validators rely on a !DOCTYPE element at the start of the XML file. For example, one can use declarations such as the following:

  1 
    <!DOCTYPE cellar-book SYSTEM "CellarBook.dtd"> 
    <cellar-book>
        <wine-catalog>
  5          ...
        </wine-catalog>
        ...
    </cellar-book>
    

The root element of the XML instance document is given as the second value, SYSTEM in third and a reference to the DTD file in fourth.