python libxml2 读取器与 XML_PARSE_RECOVER
我正在尝试让一个读取器能够从损坏的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 个回答
可以考虑使用 xml.sax
。当我遇到格式非常糟糕的 XML 文件时,里面可能会有很多不同的问题,这时候可以尝试把问题拆分成小块来处理。
你提到你有一个非常大的 XML 文件,里面可能有很多记录需要逐个处理。每条记录(比如 <item>...</item>
)都有开始标签和结束标签,这些标签可以作为你恢复的关键点。
在 xml.sax
中,你需要提供读取器、处理器和输入源。最糟糕的情况是,可能有一条记录无法恢复,但用这种方法处理问题会更有效。虽然设置起来稍微麻烦一点,但逐条解析格式不正确的数据,并记录下坏记录,可能是你能做的最好的选择。
在日志中,确保给自己足够的信息,以便重建原始记录,这样你就可以为所有可能遇到的情况添加额外的恢复代码(例如,创建一个名为 badrecords_今天的日期
.xml 的文件,以便你可以手动重新处理)。
祝你好运。
你的xml是不是以某种一致的方式坏掉了?有没有什么规律可以遵循,在解析之前修复你的xml呢?
比如说,如果错误只是因为没有处理的&符号,而你又不使用CDATA或处理指令,那么可以用正则表达式来修复它。
补充一下:可以看看Python标准库里的sgmllib。BeautifulSoup使用了它,所以在你的情况下可能会很有用。(BeautifulSoup本身只提供树形结构的表示,而不是事件处理)。
我对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)