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.
  • note must contain to, then from, then message, 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 author comes before the title, but the order must be title first.
  • The required price is missing.
  • The required id attribute on book is 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 ID value 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.
Scroll to Top