DTD全称为Document Type Definition,也就是文档类型定义,它是用来定义XML文档合法构建模块的语法规则集合,主要作用是约束XML文档的元素、属性、实体等内容的结构,确保XML文档符合预设的格式规范。

DTD的核心组成
DTD的规则主要通过三类声明来实现,分别是元素声明、属性声明和实体声明,这三类声明共同构成了XML文档的结构约束。
元素声明
元素声明用来定义XML文档中允许出现的元素名称,以及元素的内容类型和嵌套规则。基本语法格式如下:
<!ELEMENT 元素名称 元素内容规则>
常见的元素内容规则有以下几种:
- EMPTY:表示元素没有内容,比如<img/>这类空元素
- ANY:表示元素可以包含任意内容
- (#PCDATA):表示元素只能包含可解析的文本内容
- 子元素列表:比如(子元素1,子元素2)表示元素必须按顺序包含这两个子元素
属性声明
属性声明用来定义元素允许携带的属性,以及属性的类型和默认值。基本语法格式如下:
<!ATTLIST 元素名称 属性名称 属性类型 默认值>
属性类型常见的有CDATA(字符数据)、ID(唯一标识)、IDREF(引用其他ID属性的值)等,默认值可以设置为#REQUIRED(必须存在)、#IMPLIED(可选)、#FIXED(固定值)或者具体默认值。
实体声明
实体声明用来定义可复用的内容片段或者特殊字符,分为内部实体和外部实体。基本语法如下:
<!ENTITY 实体名称 "实体内容"> <!ENTITY 实体名称 SYSTEM "外部资源路径">
DTD验证XML文档结构的流程
DTD验证XML结构的过程本质是解析器按照DTD定义的规则,逐行检查XML文档的内容是否符合约束,具体流程分为以下几步:
第一步:关联DTD到XML文档
首先需要在XML文档中声明关联的DTD,DTD分为内部DTD和外部DTD两种形式。
内部DTD直接写在XML文档内部,格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 根元素名称 [
<!ELEMENT 根元素名称 (子元素+)+>
<!ELEMENT 子元素 (#PCDATA)>
]>
<根元素名称>
<子元素>内容</子元素>
</根元素名称>
外部DTD是将DTD规则写在独立的.dtd文件中,然后在XML文档中引用,格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 根元素名称 SYSTEM "规则文件.dtd">
<根元素名称>
<子元素>内容</子元素>
</根元素名称>
独立的DTD文件内容示例:
<!ELEMENT 用户列表 (用户+)> <!ELEMENT 用户 (姓名,年龄)> <!ELEMENT 姓名 (#PCDATA)> <!ELEMENT 年龄 (#PCDATA)> <!ATTLIST 用户 id ID #REQUIRED>
第二步:解析器加载DTD规则
当XML解析器读取到XML文档的<!DOCTYPE>声明后,会先加载对应的DTD规则,解析出所有元素、属性、实体的定义,构建出结构约束模型。
第三步:逐行校验XML内容
解析器会按照XML文档的顺序,依次检查以下内容是否符合DTD规则:
- 根元素名称是否和DTD中声明的根元素一致
- 每个元素的名称是否在DTD的元素声明中存在
- 元素的嵌套顺序、出现次数是否符合元素声明中的规则
- 元素携带的属性是否在属性声明中定义,属性值类型是否符合要求,必填属性是否存在
- 实体引用是否对应已声明的实体,外部实体的资源是否可访问
第四步:返回验证结果
如果所有检查都通过,说明XML文档结构符合DTD约束,验证通过;如果出现不符合规则的内容,解析器会抛出对应的错误信息,提示具体的不符合项,比如未知元素、缺少必填属性、元素嵌套顺序错误等。
DTD验证的实际示例
以下是一个完整的外部DTD验证XML的示例,首先定义user.dtd文件:
<!ELEMENT 用户列表 (用户+)> <!ELEMENT 用户 (姓名,邮箱)> <!ELEMENT 姓名 (#PCDATA)> <!ELEMENT 邮箱 (#PCDATA)> <!ATTLIST 用户 id CDATA #REQUIRED>
对应的XML文档user.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 用户列表 SYSTEM "user.dtd">
<用户列表>
<用户 id="u1">
<姓名>张三</姓名>
<邮箱>zhangsan@ipipp.com</邮箱>
</用户>
<用户 id="u2">
<姓名>李四</姓名>
<邮箱>lisi@ipipp.com</邮箱>
</用户>
</用户列表>
这个XML文档符合user.dtd的所有规则,验证会通过。如果我们将其中一个<用户>元素缺少id属性,或者把<姓名>和<邮箱>的顺序调换,解析器就会提示验证失败。
DTD的局限性
虽然DTD可以验证XML的基本结构,但它也存在一些不足,比如不支持数据类型的定义,所有属性值都只能作为字符串处理,也不支持命名空间,复杂场景下约束能力有限。因此在更复杂的XML校验场景中,通常会使用XSD(XML Schema Definition)来替代DTD,但DTD作为XML早期的结构约束标准,仍然在很多遗留系统和简单场景中被广泛使用。