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

FeatureDTDXSD
SyntaxIts own compact grammarAn XML document itself
Data typesNone — everything is textStrings, dates, integers, decimals, patterns
CardinalityCrudePrecise, via minOccurs and maxOccurs
NamespacesNot understoodFirst-class
OrderingSequence onlysequence, choice, all
ToolingLegacy, still required by RSSWidely 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 use minOccurs.
  • Restrictions can be layered with xs:restriction plus patterns or enumerations.
  • Reuse types across documents with xs:import instead 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 whenChoose JSON when
Mixed content and markup inside textRecords and API payloads
A schema and namespaces are required at the boundaryThe consumer is a browser or mobile app
You need XSLT, XPath or XQuery processingSmall payloads and simple parsing matter most
Comments and processing instructions must surviveThe 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 -20

FAQ

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.

XML syntax and well-formedness Templates and apply-templates

Last refreshed 2026-09-18.