让expat在Python中使用.dtd进行实体替换

2 投票
2 回答
1299 浏览
提问于 2025-04-15 22:59

我正在尝试读取一个看起来像这样的xml文件

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE dblp SYSTEM "dblp.dtd">
<dblp>
<incollection>
<author>Jos&eacute; A. Blakeley</author>
</incollection>
</dblp>

导致问题的地方是

Jos&eacute; A. Blakeley

部分:解析器调用它的字符处理器两次,一次是“Jos”,一次是“ A. Blakeley”。现在我明白,如果它不知道eacute实体,这可能是正确的行为。然而,这在dblp.dtd中是有定义的,而我也有这个文件。不过,我似乎无法说服expat使用这个文件。我只能说

p = xml.parsers.expat.ParserCreate()
# tried with and without following line
p.SetParamEntityParsing(xml.parsers.expat.XML_PARAM_ENTITY_PARSING_ALWAYS) 
p.UseForeignDTD(True)
f = open(dblp_file, "r")
p.ParseFile(f)

但expat仍然不识别我的实体。为什么没有办法告诉expat使用哪个DTD呢?我尝试过

  • 把文件放在和XML同一个目录下
  • 把文件放在程序的工作目录下
  • 用绝对路径替换xml文件中的引用

我漏掉了什么吗?谢谢。

2 个回答

0

顺便说一下,我可以通过把.dtd文件里相关的部分复制到XML文件里,暂时解决我的问题,就像这样:

<!DOCTYPE dblp [
    <!ENTITY Agrave  "&#192;" >
]>

不过,这并不能从根本上解决问题。

1

我理解的是,如果你直接使用pyexpat,那么你需要自己提供一个ExternalEntityRefHandler,来获取外部的DTD文件,并把它传给expat。

比如可以看看xml.sax.expatreader里的示例代码(在Python 2.6中,external_entity_ref方法在第374行)。

如果可以的话,使用像SAX这样的高级接口(通过expatreader)可能会更好。

撰写回答