python libxml2 读取器与 XML_PARSE_RECOVER

8 投票
4 回答
1626 浏览
提问于 2025-04-16 05:04

我正在尝试让一个读取器能够从损坏的XML文件中恢复。使用libxml2的XML_PARSE_RECOVER选项配合DOM API(也就是libxml2.readDoc)可以正常工作,它能解决一些实体问题。

但是,当我在读取器API中使用这个选项时(因为我们解析的文档很大,所以这个API是必需的),就不行了。它会一直卡在一个循环里(reader.Read()一直返回-1):

下面是一个小例子的代码:

import cStringIO
import libxml2

DOC = "<a>some broken & xml</a>"

reader = libxml2.readerForDoc(DOC, "urn:bogus", None, libxml2.XML_PARSE_RECOVER | libxml2.XML_PARSE_NOERROR)

ret = reader.Read()
while ret:
    print 'ret: %d' % ret
    print "node name: ", reader.Name(), reader.NodeType()
    ret = reader.Read()

有没有什么好的方法可以正确恢复呢?

4 个回答

0

可以考虑使用 xml.sax。当我遇到格式非常糟糕的 XML 文件时,里面可能会有很多不同的问题,这时候可以尝试把问题拆分成小块来处理。

你提到你有一个非常大的 XML 文件,里面可能有很多记录需要逐个处理。每条记录(比如 <item>...</item>)都有开始标签和结束标签,这些标签可以作为你恢复的关键点。

xml.sax 中,你需要提供读取器、处理器和输入源。最糟糕的情况是,可能有一条记录无法恢复,但用这种方法处理问题会更有效。虽然设置起来稍微麻烦一点,但逐条解析格式不正确的数据,并记录下坏记录,可能是你能做的最好的选择。

在日志中,确保给自己足够的信息,以便重建原始记录,这样你就可以为所有可能遇到的情况添加额外的恢复代码(例如,创建一个名为 badrecords_今天的日期.xml 的文件,以便你可以手动重新处理)。

祝你好运。

0

你的xml是不是以某种一致的方式坏掉了?有没有什么规律可以遵循,在解析之前修复你的xml呢?

比如说,如果错误只是因为没有处理的&符号,而你又不使用CDATA或处理指令,那么可以用正则表达式来修复它。

补充一下:可以看看Python标准库里的sgmllib。BeautifulSoup使用了它,所以在你的情况下可能会很有用。(BeautifulSoup本身只提供树形结构的表示,而不是事件处理)。

1

我对libxml2的绑定情况不是很了解。甚至连libxml2的网站都建议使用lxml。在lxml中解析这个树结构并忽略&的方式既简单又干净:

from cStringIO import StringIO
from lxml import etree

DOC = "<a>some broken & xml</a>"

reader = etree.XMLParser(recover=True)
tree = etree.parse(StringIO(DOC), reader)
print etree.tostring(tree.getroot())

lxml文档中的解析器页面详细介绍了如何设置解析器以及如何遍历内容。

补充:

如果你想逐步解析一个文档,可以使用XMLparser类,因为它是_FeedParser的子类:

DOC = "<a>some broken & xml</a>"
reader = etree.XMLParser(recover=True)

for data in StringIO(DOC).read():
    reader.feed(data)

tree = reader.close()
print etree.tostring(tree)

撰写回答