DTD Validation — Complete Guide to Document Type Definitions
In this tutorial, you'll learn about DTD Validation. We cover key concepts, practical examples, and best practices.
DTD (Document Type Definition) validation defines the legal structure of an XML document using declarations for elements, attributes, entities, and notations — enforcing business rules before data processing.
What You'll Learn
- Writing DTD element and attribute declarations
- Internal vs external DTDs and how to link them
- Entity declarations for reusable content and character references
- Validating XML against DTDs with tools and code
Why DTD Validation Matters
DTD validation ensures XML data meets structural requirements before your application processes it. A missing required element or an unexpected attribute can crash a parser, corrupt data, or create security vulnerabilities. Durga Antivirus Pro uses DTD validation as a first-pass check on XML threat signature files — rejecting malformed updates before they reach the scan engine.
Learning Path
flowchart LR A[XML Basics] --> B[XML DTD Doctype] B --> C[DTD Validation
You are here] C --> D[XML Schema XSD] D --> E[SOAP & WSDL]
DTD Syntax Reference
| Declaration | Syntax | Purpose |
|---|---|---|
| Element | <!ELEMENT name content> |
Define element structure |
| Attribute | <!ATTLIST elem name type default> |
Define element attributes |
| Entity | <!ENTITY name value> |
Define reusable content |
| Notation | <!NOTATION name system> |
Define data format |
Complete DTD Example
<!ELEMENT library (book+)>
<!ELEMENT book (title, author, year, price)>
<!ATTLIST book
category (fiction|non-fiction|sci-fi) "fiction"
id ID #IMPLIED>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST price
currency (USD|EUR|GBP|JPY) "USD">
Let's break down each declaration:
<!ELEMENT library (book+)>— library contains one or more book elements<!ELEMENT book (title, author, year, price)>— book must have title, author, year, price in sequence<!ATTLIST book category (fiction|non-fiction|sci-fi) "fiction">— category attribute, default "fiction"<!ATTLIST book id ID #IMPLIED>— optional ID attribute of type ID (unique)<!ELEMENT title (#PCDATA)>— title contains parsed character data (text)<!ATTLIST price currency (USD|EUR|GBP|JPY) "USD">— currency attribute with enumerated values
Internal DTD
An internal DTD is declared inside the XML document itself:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library [
<!ELEMENT library (book+)>
<!ELEMENT book (title, author, year, price)>
<!ATTLIST book category (fiction|non-fiction) "fiction">
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT price (#PCDATA)>
]>
<library>
<book category="fiction">
<title>The Hobbit</title>
<author>J.R.R. Tolkien</author>
<year>1937</year>
<price currency="USD">12.99</price>
</book>
<book category="non-fiction">
<title>A Brief History of Time</title>
<author>Stephen Hawking</author>
<year>1988</year>
<price currency="GBP">9.99</price>
</book>
</library>
Internal DTDs are useful for standalone documents that don't need to share validation rules.
External DTD
External DTDs are stored in separate .dtd files and referenced from XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library SYSTEM "library.dtd">
<library>
<book category="fiction" id="b1">
<title>The Hobbit</title>
<author>J.R.R. Tolkien</author>
<year>1937</year>
<price currency="USD">12.99</price>
</book>
</library>
The library.dtd file:
<!ELEMENT library (book+)>
<!ELEMENT book (title, author, year, price)>
<!ATTLIST book
category (fiction|non-fiction|sci-fi) "fiction"
id ID #IMPLIED>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST price
currency (USD|EUR|GBP|JPY) "USD">
External DTDs are the standard for enterprise use — one schema file validates thousands of documents.
Element Content Models
DTD defines several content models for elements:
| Model | Syntax | Example | Meaning |
|---|---|---|---|
| Empty | EMPTY |
<!ELEMENT br EMPTY> |
No content allowed |
| Text-only | (#PCDATA) |
<!ELEMENT title (#PCDATA)> |
Only text |
| Element-only | (child1, child2) |
<!ELEMENT book (title, author)> |
Only children in order |
| Mixed | (#PCDATA\|child)* |
<!ELEMENT p (#PCDATA\|b\|i)*> |
Text or children, any order |
| Any | ANY |
<!ELEMENT wrapper ANY> |
Any content (avoid) |
Occurrence Indicators
| Symbol | Meaning |
|---|---|
+ |
One or more (required, repeatable) |
* |
Zero or more (optional, repeatable) |
? |
Zero or one (optional) |
| (none) | Exactly one (required) |
<!ELEMENT library (book+)> <!-- One or more books -->
<!ELEMENT catalog (book*, magazine*)> <!-- Zero or more of each -->
<!ELEMENT chapter (title, para+)> <!-- One title, one or more paras -->
<!ELEMENT reference (author?)> <!-- Optional author -->
Attribute Types
| Type | Description | Example |
|---|---|---|
CDATA |
Character data (text) | <!ATTLIST book isbn CDATA #REQUIRED> |
ID |
Unique identifier | <!ATTLIST book id ID #REQUIRED> |
IDREF |
Reference to an ID | <!ATTLIST chapter ref IDREF #IMPLIED> |
IDREFS |
Space-separated ID list | <!ATTLIST book crossRefs IDREFS #IMPLIED> |
(val1\|val2) |
Enumerated values | <!ATTLIST book category (fiction\|non-fiction) "fiction"> |
NMTOKEN |
Name token (letters, digits) | <!ATTLIST part code NMTOKEN #REQUIRED> |
ENTITY |
Entity reference | <!ATTLIST img src ENTITY #REQUIRED> |
Attribute Defaults
| Default | Meaning |
|---|---|
#REQUIRED |
Attribute must be present |
#IMPLIED |
Attribute is optional |
"value" |
Default value if not specified |
#FIXED "value" |
Attribute must have this value |
Entity Declarations
Entities define reusable content or special characters:
<!-- General entities (used in XML content) -->
<!ENTITY author-name "DodaTech Tutorials">
<!ENTITY copyright "Copyright 2026, DodaTech.">
<!-- Parameter entities (used only in DTD) -->
<!ENTITY % book-model "(title, author, year, price)">
<!ELEMENT book %book-model;>
<!-- External entities (refer to external files) -->
<!ENTITY logo SYSTEM "logo.svg" NDATA SVG>
<!ENTITY disclaimer SYSTEM "disclaimer.xml">
Using entities in XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article [
<!ENTITY author "DodaTech">
<!ENTITY version "1.0">
]>
<article>
<title>XML DTD Guide v&version;</title>
<author>&author;</author>
<body>This guide covers DTD validation.</body>
</article>
Expected output when parsed:
<?xml version="1.0" encoding="UTF-8"?>
<article>
<title>XML DTD Guide v1.0</title>
<author>DodaTech</author>
<body>This guide covers DTD validation.</body>
</article>
Validating XML with Tools
The xmllint command validates XML against DTD:
# Validate with internal DTD
xmllint --valid --noout document.xml
# Validate with external DTD
xmllint --dtdvalid library.dtd --noout library.xml
# Show validation output
xmllint --dtdvalid library.dtd library.xml
Expected output for valid XML:
(no output — exit code 0)
Expected output for invalid XML:
library.xml:5: element year: validity error: Element year content does not follow
the DTD, expecting (#PCDATA), got '19xy'
library.xml fails to validate
Validating with Python
from lxml import etree
# Parse DTD
dtd = etree.DTD(open('library.dtd', 'rb').read())
# Parse XML
xml = etree.parse('library.xml')
# Validate
if dtd.validate(xml):
print("XML document is valid against the DTD.")
else:
print("Validation errors:")
for error in dtd.error_log.filter_from_errors():
print(f" Line {error.line}: {error.message}")
# Expected output (valid):
# XML document is valid against the DTD.
# Expected output (invalid):
# Validation errors:
# Line 3: Element book content does not follow the DTD,
# expecting (title, author, year, price), got (title, author, price, year)
Security Angle
DTDs can be dangerous. External entity references in DTDs enable XXE attacks:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
This DTD instructs the parser to read /etc/passwd and include its contents. Durga Antivirus Pro strips DTD declarations from untrusted XML files before processing and validates all XML against a predefined schema rather than allowing inline DTDs. Always disable external entity resolution on production parsers.
DTD vs XSD
| Feature | DTD | XSD (XML Schema) |
|---|---|---|
| Syntax | Non-XML (custom) | XML |
| Data types | Only text (PCDATA) | Strings, numbers, dates, etc. |
| Namespace support | No | Yes |
| Extensibility | Limited | Via inheritance and substitution |
| Regex patterns | No | Yes (via pattern facet) |
| Documentation | No | Via xs:annotation |
| Processing | Parsers support universally | Requires schema-aware parser |
Common Mistakes
1. Forgetting the DOCTYPE declaration
Without <!DOCTYPE ...>, the parser does not validate. It checks well-formedness only.
2. Wrong order of child elements in content model
(title, author, year, price) requires this exact order. If the XML has (title, year, author, price), validation fails.
3. Using #PCDATA in an element that needs children
(#PCDATA) means text only. For child elements, use the element names. For mixed content, use (#PCDATA|child)*.
4. Not using + for required repeated elements
(book) means exactly one book. (book+) means one or more. (book*) means zero or more. Choose the right indicator.
5. Forgetting that DTD is not namespace-aware
DTD treats xmlns:prefix="uri" as an attribute named xmlns:prefix. It does not understand XML namespaces.
Practice Questions
What is the difference between internal and external DTD? Internal DTD is declared inside the XML document using
<!DOCTYPE ... [...]>. External DTD is a separate.dtdfile referenced by SYSTEM or PUBLIC identifier.What does the
+indicator mean in a DTD content model? One or more occurrences of the preceding element. For example,(book+)means at least one book is required.What is an XXE attack and how does it relate to DTD? XXE (XML External Entity) attacks use DTD entity declarations to read local files or perform SSRF attacks by referencing external resources. Prevention requires disabling external entity resolution.
Challenge: Write a DTD for an invoice XML that includes an invoice number (required ID), date (required), customer name and address, one or more line items (each with product code, description, quantity, unit price), and a total. Add attribute validations for currency and tax rate.
FAQ
Try It Yourself
Validate an XML file with an external DTD:
# Create library.dtd
cat > library.dtd << 'EOF'
<!ELEMENT library (book+)>
<!ELEMENT book (title, author, year, price)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT price (#PCDATA)>
EOF
# Create XML referencing the DTD
cat > test.xml << 'EOF'
<?xml version="1.0"?>
<!DOCTYPE library SYSTEM "library.dtd">
<library>
<book><title>Test</title><author>Me</author><year>2026</year><price>9.99</price></book>
</library>
EOF
# Validate
xmllint --valid --noout test.xml && echo "Valid!"
What's Next
| Tutorial | What You'll Learn |
|---|---|
| XML Basics — Complete Guide | Foundational XML concepts |
| XML Schema Datatypes | Advanced XSD datatypes and validation |
| XPath Explained — Querying XML | Navigate XML documents with path expressions |
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-23.
What's Next
Congratulations on completing this DTD Validation tutorial! Here's where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Create a DTD for a real data format like a recipe catalog
- Explore related topics — Check out other XML tutorials in this category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro