DTD 教程
DTD 教程
DTD(Document Type Definition,文档类型定义)用于定义 XML 文档的结构规则,声明合法的元素、属性、实体,是 XML 的两种验证方式之一(另一种是 XML Schema)。
DTD 作用
- 定义结构:规定哪些元素可以出现、顺序与次数
- 验证文档:确保 XML 符合约定规则
- 共享标准:多系统间约定数据格式
- 实体定义:定义可复用内容与外部引用
DTD 与 XML Schema
| 对比项 | DTD | XML Schema(XSD) |
|---|---|---|
| 语法 | 非 XML | XML |
| 数据类型 | 有限 | 丰富 |
| 命名空间 | 不支持 | 支持 |
| 约束能力 | 较弱 | 强(Facet 等) |
| 扩展性 | 低 | 高 |
DTD 声明方式
# 内部 DTD <!DOCTYPE 根元素 [ 内部声明 ]> # 外部 DTD <!DOCTYPE 根元素 SYSTEM "file.dtd"> <!DOCTYPE 根元素 PUBLIC "公共标识" "url.dtd">
学习路线
- 简介与构建模块
- 元素与属性定义
- 实体与验证
- 实例与总结
DTD 简介
DTD 简介
1. 什么是 DTD
DTD 是 SGML/XML 的文档类型定义,规定文档的逻辑结构:元素、属性、实体及其关系。合法的 XML 文档必须满足其 DTD 规则。
2. DTD 类型
# 内部 DTD(文档内部声明) <!DOCTYPE note [ <!ELEMENT note (to, from, body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT body (#PCDATA)> ]> # 外部 DTD(独立文件) <!DOCTYPE note SYSTEM "note.dtd"> # 公共 DTD(标准定义) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3. 合法文档示例
<?xml version="1.0"?> <!DOCTYPE note [ <!ELEMENT note (to, from, body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT body (#PCDATA)> ]> <note> <to>张三</to> <from>李四</from> <body>你好!</body> </note>
4. 验证工具
# 命令行验证
xmllint --noout --valid file.xml
# 在线验证
# 各类 XML 验证器
# 编程验证(Python lxml)
from lxml import etree
dtd = etree.DTD("note.dtd")
doc = etree.parse("note.xml")
print(dtd.validate(doc)) # True/False
DTD 构建模块
DTD 构建模块
1. 核心概念
# 元素(Element) # 文档的基本组成部分 <!ELEMENT 元素名 内容模型> # 属性(Attribute) # 元素的附加信息 <!ATTLIST 元素名 属性名 类型 默认值> # 实体(Entity) # 可复用的内容或引用 <!ENTITY 实体名 "值"> # PCDATA(可解析字符数据) # 文本内容,可包含其他元素 # 类似 HTML 的混合内容 # CDATA(字符数据) # 原始文本,不解析标记
2. 元素内容类型
# 空元素 <!ELEMENT br EMPTY> # 任意内容 <!ELEMENT any ANY> # 仅文本 <!ELEMENT title (#PCDATA)> # 子元素 <!ELEMENT book (title, author, price)> # 混合内容(文本 + 子元素) <!ELEMENT p (#PCDATA | b | i)*>
3. 子元素规则
# 必须按顺序 <!ELEMENT book (title, author, price)> # 选择(任一) <!ELEMENT color (red | green | blue)> # 组合 <!ELEMENT family (name, (father | mother), children)>
4. 出现次数
# 次数修饰符 ? 出现 0 或 1 次 * 出现 0 或多次 + 出现 1 或多次 # 示例 <!ELEMENT book (title, author?, price*)> # title 必须 1 次 # author 可选 0-1 次 # price 可 0-多次 # 无修饰符 = 恰好 1 次 <!ELEMENT note (to, from)>
DTD 元素
DTD 元素
1. 声明语法
<!ELEMENT 元素名 内容> # 内容类型 EMPTY 空元素 ANY 任意内容 (#PCDATA) 文本内容 (子元素列表) 子元素 (混合内容) 文本+子元素
2. 常见声明
# 空元素(如
、) <!ELEMENT br EMPTY> <!ELEMENT img EMPTY> # 任意内容(宽松) <!ELEMENT note ANY> # 文本元素 <!ELEMENT title (#PCDATA)> # 子元素(有序) <!ELEMENT book (title, author, price)> # 可重复元素 <!ELEMENT library (book+)> <!ELEMENT book (title, author)> # 混合内容 <!ELEMENT para (#PCDATA | b | i | u)*>
3. 完整图书 DTD
<!ELEMENT bookstore (book+)>
<!ELEMENT book (title, author, year?, price)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT price (#PCDATA)>
# 对应 XML
<bookstore>
<book>
<title>XML 入门</title>
<author>张三</author>
<year>2026</year>
<price>59.9</price>
</book>
</bookstore>
4. 嵌套元素
<!ELEMENT person (name, address)> <!ELEMENT address (city, street, zip)> <!ELEMENT city (#PCDATA)> <!ELEMENT street (#PCDATA)> <!ELEMENT zip (#PCDATA)>
DTD 属性
DTD 属性
1. 属性声明语法
<!ATTLIST 元素名 属性名1 类型 默认值 属性名2 类型 默认值 > # 示例 <!ATTLIST img src CDATA #REQUIRED alt CDATA #IMPLIED width CDATA #IMPLIED >
2. 属性类型
CDATA 字符串 ID 唯一标识(不能数字开头) IDREF 引用其他 ID IDREFS 多个 ID 引用(空格分隔) ENTITY 实体引用 ENTITIES 多个实体 NMTOKEN 名称字符 NMTOKENS 多个名称字符 NOTATION 表示法 (枚举值) 取值列表
3. 默认值
#REQUIRED 必须提供 #IMPLIED 可选 #FIXED "值" 固定值(不能修改) "值" 默认值(可覆盖) # 示例 <!ATTLIST book id CDATA #REQUIRED lang CDATA "zh" edition CDATA #FIXED "1.0" note CDATA #IMPLIED > # XML 中使用 <book id="b1" lang="en">...</book> # id 必须,lang 默认 zh 可改 # edition 固定 1.0,note 可选
4. 枚举属性
# 只能取列表中的值 <!ATTLIST color value (red | green | blue) #REQUIRED > <!ATTLIST gender value (男 | 女) "男" > # 用法 <color value="red"/> <gender value="女"/>
5. 完整属性示例
<!ATTLIST person id ID #REQUIRED name CDATA #REQUIRED email CDATA #IMPLIED status (active | inactive) "active" manager IDREF #IMPLIED skills IDREFS #IMPLIED > # XML <person id="p1" name="张三" email="zhang@example.com" status="active" manager="p2" skills="s1 s2 s3">
XML 元素和属性比较
XML 元素和属性比较
1. 两种表达数据的方式
# 用元素存数据 <person> <name>张三</name> <age>30</age> </person> # 用属性存数据 <person name="张三" age="30"/> # 混合 <person name="张三"> <age>30</age> </person>
2. 使用原则
# 建议用元素的场景 - 数据是文档主要内容 - 数据较长(大段文本) - 数据有复杂结构 - 数据需要扩展子内容 # 建议用属性的场景 - 数据是元信息(标识符) - 数据是配置(类别/语言) - 数据是简单枚举 - 数据与元素强相关(修饰)
3. 实践建议
# 行业惯例 # 简单数据: 属性更简洁 # 复杂数据: 元素更可扩展 # DTD 中的选择 # 属性: CDATA/枚举等简单类型 # 元素: 任意结构 # 注意 # 属性值不能包含复杂结构 # 元素可嵌套任意深度
4. 示例对比
# 方式一:全属性
<book title="XML" author="张三"
price="59.9" year="2026"/>
# 方式二:全元素
<book>
<title>XML</title>
<author>张三</author>
<price>59.9</price>
<year>2026</year>
</book>
# 方式三:混合(推荐场景)
<book category="技术">
<title>XML</title>
<author>张三</author>
</book>
DTD 实体
DTD 实体
1. 什么是实体
实体(Entity)是 DTD 中定义的命名内容,可在文档中引用,用于避免重复、简化维护。
2. 内部实体
# 定义 <!DOCTYPE note [ <!ENTITY author "张三"> <!ENTITY copyright "© 2026 知识出版社"> ]> # 使用(&实体名;) <note> <author>&author;</author> <copyright>©right;</copyright> </note>
3. 外部实体
# 引用外部文件内容 <!ENTITY logo SYSTEM "logo.xml"> <!ENTITY footer SYSTEM "footer.txt"> # 公共实体 <!ENTITY html PUBLIC "-//W3C//DTD XHTML 1.0//EN" "xhtml.dtd"> # 使用 <body> &logo; ... </body>
4. 参数实体
# 参数实体:用于 DTD 内部复用(以 % 定义) <!ENTITY % 通用属性 "id CDATA #IMPLIED lang CDATA 'zh'"> <!ATTLIST book %通用属性;> <!ATTLIST author %通用属性;> # 引用外部 DTD 片段 <!ENTITY % html SYSTEM "html-entities.dtd"> %html;
5. 实体安全注意
# 安全警告:XXE(XML 外部实体注入)
# 恶意 DTD 可读取本地文件
<!ENTITY xxe SYSTEM "file:///etc/passwd">
# 防护
# 解析器禁用外部实体
from lxml import etree
parser = etree.XMLParser(resolve_entities=False)
# Java
DocumentBuilderFactory
.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)
DTD 验证
DTD 验证
1. 什么是验证
验证是检查 XML 文档是否符合 DTD 规则的过程。满足规则称为"有效(Valid)",仅格式正确称为"良构(Well-formed)"。
# 良构(Well-formed) - 标签正确闭合 - 属性加引号 - 正确嵌套 - 单一根元素 # 有效(Valid) - 良构 - 符合 DTD 规则(元素/属性/顺序)
2. 验证工具
# xmllint
xmllint --noout --valid note.xml
# Python(lxml)
from lxml import etree
# 方式一:DTD 文件
dtd = etree.DTD("note.dtd")
doc = etree.parse("note.xml")
print("有效:", dtd.validate(doc))
print("错误:", dtd.error_log.last_error)
# 方式二:内联 DTD(自动验证)
doc = etree.parse("note.xml")
print(doc.docinfo.doctype)
# Java
import javax.xml.parsers.*;
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setValidating(true);
3. 常见验证错误
# 1. 元素缺失/多余 # 预期 (title, author) 实际只有 title # 错误: Element 'book' content does not follow the DTD # 2. 元素顺序错误 # 预期 (title, author) 实际 (author, title) # 3. 属性缺失 # 预期 id CDATA #REQUIRED 但未提供 # 4. 枚举值不合法 # 预期 (red|green) 实际 blue
4. 验证策略
# 何时用 DTD - 简单结构定义 - 旧系统兼容 - 教学/简单配置 # 何时用 XSD - 需要强类型 - 需要命名空间 - 复杂约束 # 何时不用验证 - 内部使用的宽松 XML - 性能敏感场景(验证有开销)
DTD 实例
DTD 实例
1. 实例:员工信息
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE company [
<!ELEMENT company (employee+)>
<!ELEMENT employee (name, department, salary?, email?)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT department (#PCDATA)>
<!ELEMENT salary (#PCDATA)>
<!ELEMENT email (#PCDATA)>
<!ATTLIST employee
id ID #REQUIRED
status (active | inactive) "active"
>
]>
<company>
<employee id="e1" status="active">
<name>张三</name>
<department>技术部</department>
<salary>15000</salary>
<email>zhang@example.com</email>
</employee>
<employee id="e2">
<name>李四</name>
<department>市场部</department>
</employee>
</company>
2. 实例:配置管理
<!DOCTYPE config [ <!ELEMENT config (app, database, server*)> <!ELEMENT app (name, version, debug)> <!ELEMENT name (#PCDATA)> <!ELEMENT version (#PCDATA)> <!ELEMENT debug (#PCDATA)> <!ELEMENT database (host, port, user)> <!ELEMENT host (#PCDATA)> <!ELEMENT port (#PCDATA)> <!ELEMENT user (#PCDATA)> <!ELEMENT server (ip, role)> <!ELEMENT ip (#PCDATA)> <!ELEMENT role (#PCDATA)> <!ATTLIST server type (web | db | cache) "web"> ]>
3. 实例:订单数据
<!DOCTYPE order [ <!ELEMENT order (customer, items)> <!ELEMENT customer (name, address?)> <!ELEMENT address (city, street)> <!ELEMENT city (#PCDATA)> <!ELEMENT street (#PCDATA)> <!ELEMENT items (item+)> <!ELEMENT item (product, qty, price)> <!ELEMENT product (#PCDATA)> <!ELEMENT qty (#PCDATA)> <!ELEMENT price (#PCDATA)> <!ATTLIST order id CDATA #REQUIRED date CDATA #IMPLIED> ]>
DTD 总结
DTD 总结
1. 核心要点
- 元素:<!ELEMENT> 定义文档结构
- 属性:<!ATTLIST> 定义元素附加信息
- 实体:<!ENTITY> 定义可复用内容
- 验证:确保 XML 符合定义的规则
2. 声明速查
<!ELEMENT 名 (内容)> EMPTY / ANY / (#PCDATA) / (子元素) / (混合) 修饰符: ? 0-1次 * 0-多次 + 1-多次 <!ATTLIST 元素 属性 类型 默认> 类型: CDATA ID IDREF (枚举)... 默认: #REQUIRED #IMPLIED #FIXED "值" "值" <!ENTITY 名 "值"> 使用: &名; 参数实体: %名;
3. DTD 的优缺点
# 优点 - 语法简单,学习成本低 - 广泛支持(所有 XML 解析器) - 适合简单结构定义 # 缺点 - 非 XML 语法(工具支持差) - 无数据类型(全是文本) - 不支持命名空间 - 约束能力弱 - 不可编程扩展
4. 何时使用
- 简单配置文档
- 旧系统/标准(XHTML、RSS 1.0)
- 需要轻量验证的场景
- 新项目推荐 XML Schema 或 JSON Schema
5. 进阶方向
# 从 DTD 升级 - XML Schema(XSD): 类型化、命名空间 - RELAX NG: 简洁强大的模式语言 - JSON Schema: JSON 数据验证 - Schematron: 断言式规则 # 现代实践 # 大多数新项目用 JSON + JSON Schema # XML 主要用于文档与遗留系统
第 1 / 10 节