DTD and XML Schema
Well-formed and valid
- Well-formed means a document follows XML's syntax rules: one root, closed and properly nested tags, quoted attributes.
- Valid means it's well-formed and follows a particular structure: which elements are allowed, in what order, how many times, and what their values may be.
That structure is described in a DTD or an XML Schema. A program receiving XML can validate it first, and reject a bad document before trying to use it.
A DTD
A Document Type Definition can sit inside the document itself:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library [
<!ELEMENT library (book+)>
<!ELEMENT book (title, author+, price?)>
<!ATTLIST book id ID #REQUIRED
lang CDATA "en">
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT price (#PCDATA)>
]>
<library>
<book id="b1">
<title>Clean Code</title>
<author>Robert C. Martin</author>
<price>32.50</price>
</book>
<book id="b2" lang="fr">
<title>Le Petit Prince</title>
<author>Antoine de Saint-Exupery</author>
</book>
</library>| DTD syntax | Means |
|---|---|
(title, author+, price?) | these children, in this order |
x | exactly one |
x? | zero or one |
x+ | one or more |
x* | zero or more |
(a | b) | either a or b |
#PCDATA | text |
ID | a value unique in the whole document |
#REQUIRED, #IMPLIED | the attribute must appear / may be left out |
"en" | a default value |
This document is valid: each book has a title, at least one author, and an optional price.
Well-formed but invalid
Change the second book like this, and the document is still perfectly well-formed:
<book id="b2" lang="fr">
<title>Le Petit Prince</title>
<rating>5</rating>
</book>But it's no longer valid. The DTD never declared a rating element, and the book has lost its required author. A validator stops at the first problem:
No declaration for element rating, line 19, column 23XML Schema
An XML Schema (XSD) does the same job, with two big advantages: it's written in XML itself, and it has data types.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="library">
<xs:complexType>
<xs:sequence>
<xs:element name="book" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string" maxOccurs="unbounded"/>
<xs:element name="price" type="xs:decimal" minOccurs="0"/>
<xs:element name="published" type="xs:date" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="lang" type="xs:language" default="en"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>minOccursandmaxOccurssay how many times an element may appear (both default to 1).type="xs:decimal"andtype="xs:date"demand a number and a date inYYYY-MM-DDform. A DTD can only say "text".use="required"makes an attribute compulsory.
Now validate this document against it:
<library>
<book id="b1">
<title>Clean Code</title>
<author>Robert C. Martin</author>
<price>thirty</price>
<published>01/08/2008</published>
</book>
<book>
<author>Somebody</author>
</book>
</library>It's well-formed, as the runner confirms, but the schema finds four problems:
line 5: Element 'price': 'thirty' is not a valid value of the atomic type 'xs:decimal'.
line 6: Element 'published': '01/08/2008' is not a valid value of the atomic type 'xs:date'.
line 8: Element 'book': The attribute 'id' is required but missing.
line 9: Element 'author': This element is not expected. Expected is ( title ).Validating for real
With Python and the lxml package:
from lxml import etree
schema = etree.XMLSchema(etree.parse("library.xsd"))
doc = etree.parse("library.xml")
if not schema.validate(doc):
for error in schema.error_log:
print(error.line, error.message)Or on the command line, with xmllint, which comes with libxml2:
xmllint --noout --schema library.xsd library.xml
xmllint --noout --valid library.xml # validate against the document's DTDDTD or XML Schema?
| DTD | XML Schema | |
|---|---|---|
| written in | its own syntax | XML |
| data types | none: everything is text | dozens: numbers, dates, booleans, patterns |
| namespaces | not supported | supported |
| typical use | older formats, simple documents | modern data exchange, web services, configuration |