DTD是Document Type Definition的缩写,中文叫做文档类型定义。它是一套用来描述XML文档结构的规则集合,可以定义允许出现的元素、元素的顺序、元素能包含的属性以及实体等内容。借助DTD,接收方在解析XML之前就能知道数据应该长什么样,从而减少格式错误。

DTD的主要作用
在没有DTD的情况下,XML仅仅是一个格式良好的文本,任何标签都可以随意写。引入DTD之后,我们等于给文档立了一个规矩:
- 限定有哪些元素可以使用,比如只能有<user>和<name>
- 规定元素之间的父子关系与出现次数
- 定义属性以及属性是否必须填写
- 声明实体,简化重复内容书写
如何在XML中声明DTD
在XML里声明DTD一般分为内部声明和外部声明两种形式。
内部DTD声明
内部DTD直接写在XML文件顶部,使用<!DOCTYPE>语法。下面是一个简单的例子:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE note [ <!ELEMENT note (to, from, body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT body (#PCDATA)> ]> <note> <to>小明</to> <from>小红</from> <body>记得开会</body> </note>
上面代码中,<!DOCTYPE note [...]>就是内部DTD声明,方括号里定义了note元素必须依次包含to、from、body三个子元素,且它们都只能是文本。
外部DTD声明
如果DTD内容很多或者多个XML共用一套规则,可以把DTD写进独立文件,再在XML中引用。假设我们有一个note.dtd文件:
<!ELEMENT note (to, from, body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT body (#PCDATA)>
XML文件里这样声明:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE note SYSTEM "note.dtd"> <note> <to>小李</to> <from>小王</from> <body>资料已发</body> </note>
其中SYSTEM表示使用本地系统上的外部DTD文件。如果是公开标准,也可以使用PUBLIC加上公共标识符。
使用DTD需要注意的地方
DTD虽然古老,但在很多旧系统里依然常见。它不支持数据类型细分,也不能描述命名空间,所以后来出现了XML Schema。不过学习DTD能帮我们快速理解XML约束的基本思路。
小结:DTD就是给XML定的结构规矩,写法是<!DOCTYPE>加元素声明,可内嵌也可外引。
用Python校验带DTD的XML
我们可以用Python标准库快速验证XML是否符合DTD:
import xml.etree.ElementTree as ET
# 读取带内部DTD的xml文本
xml_text = '''<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to, from)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
]>
<note><to>a</to><from>b</from></note>'''
try:
ET.fromstring(xml_text)
print('XML格式解析成功')
except ET.ParseError as e:
print('解析出错:', e)
这段代码演示了如何载入一段包含DTD声明的XML字符串并做基础解析,实际项目中可结合lxml等库做严格的DTD校验。