DTD 实体声明
本章定位 :掌握 DTD 中三种实体的定义和使用——内部一般实体、外部实体、参数实体。理解实体引用机制如何实现文本复用和 DTD 模块化。
定义与作用
实体 (Entity)是 XML 中的"宏"——一个名字代表一段文本或外部资源。当 XML 解析器遇到 &name; 时,会用实体的定义内容替换它。
DTD 支持三种实体类型:
- 内部一般实体 :在 DTD 中定义的文本常量,XML 文档中用
&name;引用 - 外部实体 :引用外部文件的内容
- 参数实体 :仅在 DTD 内部使用的实体,用于模块化 DTD 定义
实体引用的核心价值是 DRY(Don't Repeat Yourself)——多处用到的文本只定义一次。
核心原理:实体引用替换流程
图解释 :解析器在遇到 &entity; 时查 DTD 的实体表,找到定义后用替换文本继续解析。外部实体的替换文本可能来自另一个文件。
语法/结构要点
三种实体对比
| 类型 | 声明语法 | 引用语法 | 使用范围 |
|---|---|---|---|
| 内部一般实体 | <!ENTITY name "value"> | &name; | XML 文档中 |
| 外部实体 | <!ENTITY name SYSTEM "file"> | &name; | XML 文档中 |
| 参数实体 | <!ENTITY % name "value"> | %name; | 仅在 DTD 内 |
5 个预定义实体(不需要声明)
| 字符 | 实体引用 |
|---|---|
< | < |
> | > |
& | & |
' | ' |
" | " |
完整示例:大翔用实体管理公司信息
场景说明
飞翔科技的运维 大翔 要为公司的 50 个 XML 配置文件中统一写入公司信息。如果每个文件都硬编码公司名称和版权声明,一旦公司改名或版权更新需要修改 50 个文件。大翔决定用外部实体来解决。
操作前:信息硬编码在每个文件中
<?xml version="1.0" encoding="UTF-8"?>
<config>
<company>广州飞翔科技有限公司</company>
<copyright>Copyright 2026 飞翔科技. All rights reserved.</copyright>
<contact>support@learnto.cn</contact>
<app-settings>
<version>3.2.1</version>
</app-settings>
</config>
操作后:实体复用
common.ent (公共实体文件):
<!ENTITY company "广州飞翔科技有限公司">
<!ENTITY copyright "Copyright 2026 飞翔科技. All rights reserved.">
<!ENTITY contact "support@learnto.cn">
app-config.xml (配置文件):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config [
<!ENTITY % common SYSTEM "common.ent">
%common;
]>
<config>
<company>&company;</company>
<copyright>©right;</copyright>
<contact>&contact;</contact>
<app-settings>
<version>3.2.1</version>
</app-settings>
</config>
操作结果
现在,50 个 XML 文件都引用同一个 common.ent。如果公司改名或版权更新,只需修改 common.ent 一个文件,重新解析所有 XML 即可生效。大翔的总操作时间从 2 小时缩短到 2 分钟。
易错场景
错误一:在实体值中使用 & 而不转义
<!-- ❌ -->
<!ENTITY corp "乐途 & 伙伴">
<!-- ✅ -->
<!ENTITY corp "乐途 & 伙伴">
错误二:参数实体引用在 DTD 外部
<!ENTITY % common "value1 | value2">
%common; <!-- ✅ 在 DTD 中引用 -->
<!-- 在 XML 文档中使用 %common; ❌ -->
参数实体只能在 DTD 声明中使用(包括内部子集和外部 DTD 文件),不能在 XML 文档内容中使用。
错误三:实体循环引用
<!-- ❌ 致命错误 -->
<!ENTITY a "&b;">
<!ENTITY b "&a;">
面试考点
| 考点 | 参考答案要点 |
|---|---|
| XML 中有哪些预定义实体?为什么需要它们? | 5 个:< <、> >、& &、' '、" "。因为 XML 解析器把 < 和 & 视为特殊字符,直接用会破坏语法 |
| 一般实体和参数实体的区别? | 一般实体在 XML 文档中用 &name; 引用,参数实体用 %name; 引用且只能在 DTD 内部使用。参数实体常用于模块化 DTD |
| 外部实体的安全风险? | 外部实体可能被利用进行 XXE 攻击(读取服务器文件、发起 SSRF 请求)。现代 XML 解析器默认禁用外部实体 |