9. XML DTD
What you will learn
- What a DTD is and what it checks
- How to declare elements, attributes, and entities
- Internal and external DTDs
- The limits of DTDs, and a security warning
What is a DTD?
A DTD (Document Type Definition) is a set of rules that describes which elements and attributes an XML document may contain, and in what arrangement. A file that obeys the rules is valid, as you learned in the last lesson.
DTDs are older and simpler than XML Schema. You will still meet them in older systems and in HTML history, so it is worth knowing the basics.
A first example
XML code: note.xml (with an internal DTD)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ELEMENT note (to, from, message)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT message (#PCDATA)>
]>
<note>
<to>Ali</to>
<from>Sam</from>
<message>See you at noon.</message>
</note>
What the rules say
- The root is
note. notemust containto, thenfrom, thenmessage, in that order.- Each of those holds plain text (
#PCDATA, meaning “parsed character data”).
The document obeys every rule, so it is valid.
Element declarations
The form is <!ELEMENT name content-rule>.
| Rule | Meaning |
|---|---|
(#PCDATA) |
Text only |
EMPTY |
No content |
ANY |
Anything (rarely a good idea) |
(a, b, c) |
These children, in this order |
(a | b) |
Either a or b |
(#PCDATA | b | i)* |
Mixed content: text with b and i elements |
How many times? The counters
| Symbol | Meaning | Example |
|---|---|---|
| (none) | Exactly once | title |
? |
Zero or one (optional) | subtitle? |
* |
Zero or more | author* |
+ |
One or more | author+ |
XML code: library.dtd
<!ELEMENT library (book+)>
<!ELEMENT book (title, subtitle?, author+, price)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT subtitle (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT price (#PCDATA)>
What the rules say
A library holds one or more book elements. Each book must have a title, may have one subtitle, must have at least one author, and must have a price, in that order.
Attribute declarations
The form is <!ATTLIST element attribute type default>.
XML code
<!ATTLIST book
id ID #REQUIRED
language CDATA #IMPLIED
format (paper | ebook) "paper"
>
| Part | Meaning |
|---|---|
CDATA |
Any text |
ID |
A unique name within the document |
(paper | ebook) |
Only one of the listed values |
#REQUIRED |
The attribute must be present |
#IMPLIED |
Optional |
"paper" |
A default value used when the attribute is missing |
An ID value must start with a letter or underscore, so b1 works but 1 does not.
Entities
A DTD can define your own shortcuts, called entities.
XML code
<!DOCTYPE page [
<!ENTITY company "BeingXpert Learning">
]>
<page>Welcome to &company;!</page>
What the text means after parsing
Welcome to BeingXpert Learning!
Internal and external DTDs
- An internal DTD sits inside the file, in the
DOCTYPE, as above. It applies to that file only. - An external DTD is a separate file, so many documents can share it.
XML code: using an external DTD
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library SYSTEM "library.dtd">
<library>
<book id="b1">
<title>Learning XML</title>
<author>Sam Rivera</author>
<price>12.00</price>
</book>
</library>
A valid and an invalid document
XML code: invalid
<library>
<book>
<author>Sam Rivera</author>
<title>Learning XML</title>
</book>
</library>
What a validator reports (wording differs between tools)
Several problems against the rules above:
- The
authorcomes before thetitle, but the order must be title first. - The required
priceis missing. - The required
idattribute onbookis missing.
The file is still well-formed, but it is not valid.
How to validate against a DTD
Browsers only check well-formedness, so you need a validator. Options are an editor extension, a command-line tool such as xmllint (xmllint --noout --valid library.xml), or your own code. Use made-up sample data if you try an online tool.
PHP code
<?php
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->load(__DIR__ . "/library.xml");
if ($doc->validate()) {
echo "Valid against the DTD.";
} else {
foreach (libxml_get_errors() as $error) {
echo htmlspecialchars(trim($error->message), ENT_QUOTES, "UTF-8") . "<br>";
}
libxml_clear_errors();
}
Output for the valid file
Valid against the DTD.
Security warning. DTDs can define entities that read local files or fetch addresses from the internet. Attackers use this in an attack called XXE (XML External Entity). When your program reads XML that came from someone else, turn off external entity loading, do not enable DTD processing unless you need it, and keep your XML libraries updated. Treat all outside XML as untrusted. Modern PHP versions are safe by default, but never switch on options such as LIBXML_NOENT for outside data.
Limits of DTDs
- They are not written in XML, so XML tools cannot read them like ordinary files.
- They have only a few data types: everything is text.
- They do not understand namespaces well.
- They cannot say “this must be a number from 1 to 100”.
XML Schema, the next lesson, fixes all of these, which is why it replaced DTDs for most data work.
Common mistakes
- Putting declarations in the wrong order, so the document no longer matches.
- Forgetting that
(a, b)means a fixed order, while(a | b)means a choice. - Expecting a browser to validate against a DTD.
- Using an
IDvalue that starts with a digit. - Enabling external entities on XML from outside sources.
Exercise
Write DTD rules for a pet element that contains a name (required), an optional nickname, and one or more vaccine elements, all text. Give pet a required attribute id of type ID.
Show solution
<!ELEMENT pet (name, nickname?, vaccine+)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT nickname (#PCDATA)>
<!ELEMENT vaccine (#PCDATA)>
<!ATTLIST pet id ID #REQUIRED>
Knowledge check
1. What does a DTD describe?
Which elements and attributes a document may contain, and how they are arranged.
2. What does author+ mean?
One or more author elements.
3. What is XXE, and how do you reduce the risk?
An attack using external entities. Disable external entity loading and DTD processing for untrusted XML.
Summary
- A DTD declares elements (
ELEMENT), attributes (ATTLIST), and entities (ENTITY). - Use
,for order,|for choice, and? * +for counts. - Browsers do not validate. DTDs are limited, and risky if external entities are enabled for outside XML.