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:
(#PCDATA)
(Parsed Character DATA) which corresponds to character
string information;
parsed
means that the character data can contain entity references as explained below;
a regular expression in parentheses involving other element names.
an element can also be a
Character Data fragment
enclosed between
<![CDATA[
and
]]>
which inserts its content verbatim without any interpretation. This is often
used to display XML content without having to escape the
<
and
&
.
the value of an attribute can only be a string (CDATA
) but a
DTD allows for some special case that enable some simple validations:
ID
: a string starting with a letter or an underline (_
) followed
by a sequence of letters, numbers, underlines, periods (.
)
and dashes (-
). All ID
s must be unique in the document.
IDREF
: a string that must refer to an existing
ID
in the document.
a list of strings enclosed in parenthesis and separated by a
|
. Note that this validation can only be applied on an
attribute and not on the value of an XML element."'
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‑
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‑) can contain character data and no other
elements. A
cellar
(line 3‑) is a list (possibly empty) of
wine
elements. A
name
(line 12‑) 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‑).
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
:
<
a
less-than sign
(<
) in an XML file because
<
is reserved to indicate the start of a tag;
&
As we have introduced the ampersand to indicate the start of an entity, we
need a way to insert an ampersand (&
);
"
for inserting a
"
;
'
for inserting a
'
;
>
by symmetry with
<
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‑). Its call is preceded by a percent sign instead of an
ampersand see
owner
(line 32‑) and
location
(line 33‑). Another special kind of entity,
introduced by
SYSTEM
, refers to a file such as
wine-catalog
(line 36‑). 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
ELEMENT
s and
ATTLIST
s 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)* >5 <!ELEMENT wine (purchaseDate,quantity,rating?,comment?) >
<!ELEMENT purchaseDate (#PCDATA) >
<!ELEMENT quantity (#PCDATA) >
<!ELEMENT rating EMPTY > <!ATTLIST rating stars CDATA #IMPLIED> 10 <!ATTLIST wine code IDREF #REQUIRED >
<!ELEMENT name (first | family | initial)+ >
<!ELEMENT first (#PCDATA) > <!ELEMENT family (#PCDATA) > 15 <!ELEMENT initial (#PCDATA) > <!ELEMENT cellar-book (wine-catalog, owner, location, cellar) >
<!-- [general] entities for use in instance document --> 20 <!ENTITY guy "Guy Lapalme" >
<!ENTITY eacute "é" > <!ENTITY mtl "Montréal" > <!ENTITY GL "&guy;, &mtl;" > 25 <!-- parameter entities for use within a DTD --> <!ENTITY % address "(street, city, province, postal-code)" >
<!ELEMENT street (#PCDATA) > <!ELEMENT city (#PCDATA) > <!ELEMENT province (#PCDATA) > 30 <!ELEMENT postal-code (#PCDATA) > <!ELEMENT owner (name,%address;) >
<!ELEMENT location %address; >
35 <!-- system entity for including a file --> <!ENTITY % wine-catalog SYSTEM "WineCatalog.dtd" >
%wine-catalog;
|
A cellar is a possibly empty list of wines. |
|
A wine is defined by a purchase date, a quantity, an optional rating and an optional comment. |
|
The purchase date is a string. |
|
A quantity is also a string. |
|
A code must refer to an
|
|
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. |
|
The cellar book is composed of the wine catalog, the owner, the location, and the cellar itself. |
|
Some definitions of entities and how they can be composed. |
|
Parameter entities can be used in the definition of other entities. |
|
Use of a parameterized entity defined on
line 26‑ |
|
Another use of the same parameterized entity. |
|
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‑). The attribute
format
(line 10‑) 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‑
of Example 3.2) of type
ID
and its reference in
line 10‑
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,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
| jeroboam | rehoboam | mathusalem | salmanazar | balthazar | nabuchodonosor) #REQUIRED > <!ATTLIST cat-wine code ID #REQUIRED>
<!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) >
|
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. |
|
The format is given as a list of literal values from which the actual value of the attribute must be chosen. |
|
The unique code for the wine that must bet matched by a reference at
line 10‑ |
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.