Validation with DTD and XSD
What DTDs and XSDs can express, how to write a usable schema, and when XML is still the right choice today.
DTD versus XSD
| Feature | DTD | XSD |
|---|---|---|
| Syntax | Its own compact grammar | An XML document itself |
| Data types | None — everything is text | Strings, dates, integers, decimals, patterns |
| Cardinality | Crude | Precise, via minOccurs and maxOccurs |
| Namespaces | Not understood | First-class |
| Ordering | Sequence only | sequence, choice, all |
| Tooling | Legacy, still required by RSS | Widely supported by editors and validators |
<!-- DTD: an internal subset declaring allowed children and attributes -->
<!DOCTYPE catalog [
<!ELEMENT catalog (book+)>
<!ELEMENT book (title, price)>
<!ATTLIST book id ID #REQUIRED>
<!ELEMENT title (#PCDATA)>
<!ELEMENT price (#PCDATA)>
]>
<!-- the same constraint is far more specific in XSD -->A small but real XSD
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/shop"
elementFormDefault="qualified">
<xs:element name="catalog">
<xs:complexType>
<xs:sequence>
<xs:element name="book" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="price" type="xs:decimal"/>
<xs:element name="published" type="xs:date" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="available" type="xs:boolean" default="true"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>elementFormDefault="qualified"puts locally declared elements in the target namespace — the single most common source of 'valid document, rejected' surprises.use="required"applies to attributes; elements useminOccurs.- Restrictions can be layered with
xs:restrictionplus patterns or enumerations. - Reuse types across documents with
xs:importinstead of copy-pasting definitions.
💡
Validation proves structure and type, not meaning. A schema can confirm that
price is a decimal; it cannot confirm the number is right. Semantic rules belong in application code or in Schematron assertions layered on top.When XML is still the right tool
- Document-centric content where markup inside text matters: DITA, DocBook, legal and publishing pipelines.
- Formats that already won: Office files, SVG, RSS and Atom, sitemaps, Android layouts, Maven and build descriptors.
- Streaming and transformation: SAX and XSLT process documents larger than memory, and XQuery queries them like a database.
- Contract-heavy interchange: XSD plus namespaces gives validation coverage that JSON Schema adoption still reaches unevenly.
- Entrenched enterprise interfaces: SOAP and WS-Security persist in banking, healthcare and government systems.
| Choose XML when | Choose JSON when |
|---|---|
| Mixed content and markup inside text | Records and API payloads |
| A schema and namespaces are required at the boundary | The consumer is a browser or mobile app |
| You need XSLT, XPath or XQuery processing | Small payloads and simple parsing matter most |
| Comments and processing instructions must survive | The data is all that matters |
# validate against a schema, and check well-formedness on its own
xmllint --noout --schema shop.xsd catalog.xml
xmllint --noout --dtdvalid catalog.dtd catalog.xml
xmllint --noout catalog.xml && echo "parses cleanly"
# pretty-print without reformatting semantics
xmllint --format catalog.xml | head -20FAQ
Should a brand new public API use XML?
Rarely. Choose JSON unless a consumer needs schema validation, digital signatures, or an existing XML pipeline. Existing internal SOAP interfaces are still worth maintaining, not rewriting for its own sake.
Does validation slow parsing down?
It adds schema compilation plus per-node checks, but the cost is normally small beside I/O. Compile the schema once and reuse it; do not re-read the XSD per document.
Related
XML syntax and well-formedness Templates and apply-templates
Last refreshed 2026-09-18.