DTD 验证的基本概念
DTD(Document Type Definition)是一种用于定义XML文档结构的规范,通过DTD可以验证XML文档是否符合预定义的规则。DTD验证的核心是确保XML文档的元素、属性、实体等符合预期的结构和约束。
DTD 的基本语法
DTD可以内嵌在XML文档中,也可以作为外部文件引用。以下是内嵌DTD的示例:
<!DOCTYPE bookstore [
<!ELEMENT bookstore (book+)>
<!ELEMENT book (title, author, price)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST book category CDATA #REQUIRED>
]>
<bookstore>
<book category="fiction">
<title>The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<price>10.99</price>
</book>
</bookstore>
外部DTD文件的引用
将DTD定义保存为外部文件(如bookstore.dtd),然后在XML中引用:
<!DOCTYPE bookstore SYSTEM "bookstore.dtd">
<bookstore>
<book category="fiction">
<title>The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<price>10.99</price>
</book>
</bookstore>
bookstore.dtd文件内容:
<!ELEMENT bookstore (book+)>
<!ELEMENT book (title, author, price)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST book category CDATA #REQUIRED>
DTD 元素定义
DTD通过<!ELEMENT>定义元素的结构。以下是一些常见的元素定义方式:
文本内容元素:
<!ELEMENT title (#PCDATA)>
子元素序列:
<!ELEMENT book (title, author, price)>
选择关系(或逻辑):
<!ELEMENT book (title | author | price)>
重复次数控制:
- +:至少一次
- *:零次或多次
- ?:零次或一次
<!ELEMENT bookstore (book+)>
DTD 属性定义
通过<!ATTLIST>定义元素的属性,语法如下:
<!ATTLIST element_name attribute_name attribute_type default_value>
示例:
<!ATTLIST book category CDATA #REQUIRED>
<!ATTLIST book lang CDATA #IMPLIED>
<!ATTLIST book edition CDATA "1st">
属性类型说明:
- CDATA:字符数据
- ID:唯一标识符
- IDREF:引用其他元素的ID
- ENUMERATED:枚举值(如(a|b|c))
DTD 实体定义
实体用于定义可重用的内容,分为内部实体和外部实体。
内部实体:
<!ENTITY publisher "O'Reilly Media">
外部实体:
<!ENTITY copyright SYSTEM "copyright.txt">
在XML中使用实体:
<book>
<title>Learning XML</title>
<publisher>&publisher;</publisher>
<rights>©right;</rights>
</book>
使用编程语言验证DTD
以下是使用Python和Java验证XML文档是否符合DTD的示例。
Python示例
使用lxml库验证DTD:
from lxml import etree
xml = """
<!DOCTYPE bookstore [
<!ELEMENT bookstore (book+)>
<!ELEMENT book (title, author, price)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST book category CDATA #REQUIRED>
]>
<bookstore>
<book category="fiction">
<title>The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<price>10.99</price>
</book>
</bookstore>
"""
try:
parser = etree.XMLParser(dtd_validation=True)
etree.fromstring(xml, parser)
print("XML is valid against DTD.")
except etree.XMLSyntaxError as e:
print(f"Validation error: {e}")
Java示例
使用javax.xml.validation验证DTD:
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.StringReader;
public class DTDValidator {
public static void main(String[] args) {
String xml = """
<!DOCTYPE bookstore [
<!ELEMENT bookstore (book+)>
<!ELEMENT book (title, author, price)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST book category CDATA #REQUIRED>
]>
<bookstore>
<book category="fiction">
<title>The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<price>10.99</price>
</book>
</bookstore>
""";
try {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new StreamSource(new StringReader(xml)));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new StringReader(xml)));
System.out.println("XML is valid against DTD.");
} catch (SAXException | IOException e) {
System.out.println("Validation error: " + e.getMessage());
}
}
}
DTD 的局限性
尽管DTD是XML验证的基础工具,但它存在以下局限性:
- 不支持数据类型(如整数、日期)。
- 缺乏命名空间支持。
- 语法较为简单,无法定义复杂的约束。
对于更复杂的验证需求,可以考虑使用XML Schema(XSD)或RelaxNG。

