DTD 概述
本章定位 :理解 DTD(Document Type Definition)的定义和作用——它是 XML 文档结构的"合同",定义了哪些元素可以出现、它们的顺序和内容。掌握 well-formed(格式良好)与 valid(有效)的核心区分。
定义与作用
DTD (Document Type Definition,文档类型定义)是 XML 最古老的验证方式,用于定义 XML 文档的合法结构和元素属性。
DTD 回答三个关键问题:
- 哪些元素可以出现在文档中?
- 元素之间如何嵌套(父子关系、顺序、出现次数)?
- 每个元素可以携带哪些属性?属性的类型和默认值是什么?
没有 DTD,XML 文档只要语法正确就可以被解析(称为 well-formed )。有了 DTD 并通过验证后,文档才是 valid (有效)。well-formed 是"字写对了",valid 是"话按规矩说"。
核心原理:well-formed vs valid
图解释 :well-formed 是 valid 的前提——语法错则无需检查 DTD。DTD 验证是额外的第二道关卡:即使语法全对,如果结构不符合 DTD 约定,文档仍会被标记为 invalid。
语法/结构要点
内部 DTD vs 外部 DTD
| 类型 | 语法 | 适用场景 |
|---|---|---|
| 内部 DTD | <!DOCTYPE root [ 声明... ]> | 所有声明写在 XML 文件内部,适合简单文档 |
| 外部 DTD | <!DOCTYPE root SYSTEM "file.dtd"> | DTD 独立文件,多 XML 文档共享 |
| 公共 DTD | <!DOCTYPE root PUBLIC "id" "url"> | 使用公开的标准 DTD(如 XHTML) |
核心关键字
| 关键字 | 含义 |
|---|---|
SYSTEM | DTD 在本地文件系统中 |
PUBLIC | DTD 有一个公开标识符,必要时用 URL 作为备用 |
完整示例:大翔为图书 XML 编写 DTD 验证
场景说明
飞翔科技的运维 大翔 发现生产环境的 XML 数据偶尔出现字段缺失或不规范。他决定为公司的图书 XML 添加 DTD 验证——在新数据入库前自动检查结构完整性。
操作前:无 DTD 的 XML(仅 well-formed)
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book>
<title>Learning XML</title>
<author>Erik T. Ray</author>
<price>39.95</price>
<!-- 缺少 year 字段 -->
</book>
<book>
<title>Everyday Italian</title>
<year>2005</year>
<!-- 缺少 author 字段 -->
<price>-15.00</price> <!-- 负价格不合理 -->
</book>
</bookstore>
这份 XML 是 well-formed(语法正确),但数据质量有问题:有的缺字段,有的值不合理。没有 DTD 时这些错误无法自动检测。
操作后:添加内部 DTD 验证
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE bookstore [
<!ELEMENT bookstore (book+)>
<!ELEMENT book (title, author+, year, price)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST book category CDATA #REQUIRED>
<!ATTLIST title lang CDATA #IMPLIED>
]>
<bookstore>
<book category="web">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
</bookstore>
操作结果
DTD 定义了以下约束并通过验证:
bookstore包含一个或多个book元素(book+)- 每个
book必须按顺序包含title, author, year, price(缺一不可) book的category属性是必填的(#REQUIRED)title的lang属性是可选的(#IMPLIED)
如果任何一条规则被违反,XML 验证器会明确报错。大翔把这个验证步骤集成到了 CI 流水线中。
易错场景
错误一:混淆 well-formed 和 valid
- 一个 XML 文档可能是 well-formed 但 invalid (语法对但结构不符合 DTD)
- 一个 XML 文档可能是 well-formed 且 valid (既语法正确也符合 DTD)
- 一个 XML 文档 不可能 invalid 但 well-formed (因为 invalid 的前提是 well-formed)
错误二:内部 DTD 声明位置错误
<!-- ❌ DTD 声明必须紧跟 XML 声明,不能在元素之后 -->
<?xml version="1.0"?>
<root><child/></root>
<!DOCTYPE root [...]>
<!-- ✅ 正确位置:在 XML 声明之后、根元素之前 -->
<?xml version="1.0"?>
<!DOCTYPE root [...]>
<root><child/></root>
面试考点
| 考点 | 参考答案要点 |
|---|---|
| well-formed 和 valid 的区别? | well-formed 满足语法规则(标签闭合、正确嵌套等);valid 在 well-formed 基础上还符合 DTD/XSD 定义的结构约束。well-formed 是 valid 的前提 |
| 内部 DTD 和外部 DTD 各适合什么场景? | 内部 DTD 适合简单、单文件场景;外部 DTD 适合多文档共享同一结构定义,也方便 DT D的版本管理和复用 |
| SYSTEM 和 PUBLIC 的区别? | SYSTEM 指定本地文件路径;PUBLIC 使用公开标识符,允许 XML 处理器通过目录查找 DTD,URL 仅作为备用fallback |