XML 只有五个预定义实体
XML 预定义实体只有 < > & " ' 五个,且必须带分号,任何其它实体都要先有 DTD 定义。特殊字符里必须转义的只有两个:& 和 <,> 仅在避免 ]]> 序列时转义,引号只需在与属性定界符相同时转义。转义顺序也要注意,先处理 & 再处理其它,否则会把刚生成的实体再转义一次。
基本信息
| 必须转义 | & 与 <,出现在任何位置都要转义 |
|---|---|
| 按需转义 | > 用于避免 ]]>;引号只在属性值内且与定界符相同 |
| 实体语法 | &name; 必须以分号结束,缺分号是致命错误 |
| 数字实体 | & 与 & 表示同一个字符,XML 与 HTML 通用 |
| 禁用字符 | XML 1.0 不接受绝大多数 C0 控制字符,连数字实体也无效 |
典型使用场景
- 拼装或校验接口请求体,避免因 & 未转义而解析失败
- 把用户输入写进 XML 配置或模板,防止结构被闭合标签破坏
- 处理第三方返回的 XML,遇到未定义实体报错时定位来源
- 在属性值中嵌入 URL,& 必须转义成 &
- 生成需要内嵌片段的大文本,用 CDATA 减少转义噪音
写法与替代方案
写法与替代方案
<!-- 正确转义:& 与 < 都处理了 -->
<item name="A & B">2 < 3</item>
<!-- 属性里的查询串,& 同样要转义 -->
<link href="https://example.com/a?x=1&y=2"/>
<!-- 大段文本用 CDATA,内部不能再出现 ]]> -->
<script><![CDATA[ if (a < b && c > d) { run(); } ]]></script>
<!-- 避免 ]]> 冲突时的写法:]]> -->易错点对照
| 场景 | 错误表现 | 正确做法 |
|---|---|---|
| 只转义 < 和 > | & 单独出现导致解析中止 | 先转义 &,再处理其它 |
| 属性里写成 | 报实体未定义错误 | 改用   或定义 DTD |
| 把 & 再转一次 | 显示成 &amp; 字面量 | 转义前判断是否已是实体 |
| CDATA 内写 ]]> | 内容被提前截断 | 拆成两段 CDATA 或转义为 ]]> |
| 注释里写 -- | 注释非法,解析失败 | 删除连续短横线 |
处理外部 XML 时必须关闭外部实体解析(DTD 与 XInclude 相关能力),否则可能被 XXE 读到本地文件或探测内网;即便只做大小限制,也能削弱实体递归展开造成的资源耗尽攻击。
把 HTML 片段放进 XML 经常失败,因为 HTML 的命名实体表远大于 XML 的五个。出现「实体未定义」时先确认文档类型究竟在按 HTML 还是 XML 解析,必要时统一改用数字实体。