XML实体是一段可被重复引用或用来表示特殊字符的抽象文本单元。在XML文档里,有些字符具备语法含义,例如小于号用来开启标签,如果直接写在内容中就会破坏结构。实体机制让开发者用间接方式表达这些内容,同时也支持把常用片段抽出来统一维护。理解实体的运作方式,是写出规范且安全XML的基础。

一、预定义实体
XML规范内置了五个预定义实体,用来替代会造成解析歧义的基础符号。它们不需要在DOCTYPE中声明,任何合规解析器都默认识别。当文档内容里必须出现左尖括号、右尖括号、与符号以及引号时,应优先使用预定义实体而不是原始字符。
下面是五个预定义实体及其对应字符:&表示&,<表示<,>表示>,"表示双引号,'表示单引号。例如一段文本想表达“A<B且C&D”,在XML中必须写成A<B且C&D,否则解析器会把<B当成标签起点而报错。
二、字符实体
字符实体以十进制或十六进制形式指向Unicode码点,适合表达无法直接键盘录入或者容易引起混淆的字符。十进制写法以&#开头接数字再加分号,十六进制以&#x开头接十六进制数再加分号。它和预定义实体互补,预定义只覆盖五个,字符实体能覆盖全部Unicode。
比如中文句号本身可直写,但有些控制字符必须转义。下面示例用字符实体输出一个版权符号和换行效果说明:
<note> 版权信息:© 2023 示例公司 十六进制表示空格: 这里用实体留空 </note>
使用字符实体时要注意结尾分号不能省略,且数字必须是合法码点。部分老旧解析库对十六进制支持不完整,跨系统交换文档时建议先验证对方解析能力。
三、内部通用实体
内部通用实体在DOCTYPE内部用ENTITY声明,把一段文本绑定到名称上,文档任意位置用&名称;引用。它常用于固定公司名、法律声明等重复内容,修改时只需改声明处。
以下代码展示如何声明并引用一个内部实体:
<!DOCTYPE message [ <!ENTITY company "ipipp技术团队"> <!ENTITY email "support@ipipp.com"> ]> <message> 联系&company;获取帮助,邮箱:&email; </message>
内部实体不会发起网络请求,因此没有外部加载风险。但要注意实体不可循环自引用,解析器检测到循环定义会直接抛出异常。另外实体内容里的特殊字符仍需遵守转义规则。
四、外部通用实体
外部通用实体通过SYSTEM关键字指向一个外部文件,解析时把文件内容替换进来。写法为<!ENTITY 名称 SYSTEM "URI">。这在模块化文档时很有用,但也会引入路径依赖与安全问题。
示例声明一个外部实体并引用:
<!DOCTYPE doc [ <!ENTITY footer SYSTEM "https://ipipp.com/footer.xml"> ]> <doc> 正文内容 &footer; </doc>
如果解析器开启了外部实体加载且URI可控,攻击者可构造读取本地文件的恶意XML,即XXE漏洞。生产环境应关闭外部实体解析,或严格校验URI白名单。内部网络调试时可临时开启,但上线前务必关闭。
五、参数实体
参数实体仅在DTD内部有效,名称以百分号开头,引用时也用百分号。它用来在DTD中复用结构定义,减少重复书写。普通通用实体不能在DTD声明中使用,参数实体正好填补这个空缺。
下面演示参数实体简化DTD:
<!DOCTYPE root [ <!ENTITY % field "name CDATA #REQUIRED"> <!ELEMENT user (id)> <!ATTLIST user %field;> ]> <root></root>
参数实体必须先声明后使用,且只能出现在DTD子集里。它极大提升了复杂DTD的可维护性,但也让DTD阅读门槛变高,团队内部应约定清晰的命名规范。
六、实体使用总结与建议
XML实体从特殊符号转义到内容复用形成完整体系。日常业务报文优先用预定义与字符实体处理符号冲突;内部通用实体管理固定话术;外部与参数实体在受控环境使用。安全上,永远不要信任外部输入的XML,关闭不必要的外部实体加载。
下表列出各类实体核心差异:
| 类型 | 声明位置 | 引用方式 | 安全风险 |
|---|---|---|---|
| 预定义实体 | 内置 | <等 | 无 |
| 字符实体 | 内置 | &#数字; | 无 |
| 内部通用 | DOCTYPE | &名称; | 低 |
| 外部通用 | DOCTYPE | &名称; | XXE |
| 参数实体 | DTD内 | %名称; | 中 |
掌握上述分类与写法,就能在大部分XML场景中正确且安全地运用实体,避免解析异常与信息泄露。
XMLXML_entityDOCTYPE修改时间:2026-08-08 16:06:31