使用lxml解析包含多个xml文档的文件

时间:2015-07-13 19:46:03

标签: python xml lxml

因此,我认为这是一个非常典型的用例,但我无法在lxml文档中找到有关此支持的任何内容。基本上我有一个xml文件,其中包含许多不同的xml文档(特别是评论)结构大致是:

<review>
    <!-- A bunch of metadata -->
</review>
<!-- The issue is here -->
<review>
    <!-- A bunch of metadata -->
</review>

基本上,我尝试像这样读取文件:

import lxml

document = lxml.etree.fromstring(open(xml_file).read())

但是当我这样做时出现错误:

lxml.etree.XMLSyntaxError: Extra content at the end of the document

完全合理的错误,实际上它是一个xml错误,应该这样对待,但我的问题是:如何让lxml认识到这是一个xml文档列表并进行相应的解析?

list_of_reviews = lxml.magic(open(xml_file).read())

magic是真正的lxml功能吗?

2 个答案:

答案 0 :(得分:1)

所以,它有点hacky,但应该相对健壮。这里有两个主要的负面因素:

  • 重复调用fromstring意味着此代码不是非常快。大约与单独解析每个文档的速度相同,比所有文档都要慢得多
  • 相对于文档中的当前位置抛出错误。添加相对位置支持(只需添加累加器以跟踪当前位置)很容易。

基本上,方法是查找抛出的错误,然后解析错误上方的文件部分。如果抛出了与最后一个根节点无​​关的错误,那么它将像典型的异常一样处理。

def fix_xml_list(test_file):
    documents = []
    finished = False
    while not finished:
        try:
            lxml.etree.fromstring(test_file)
        except XMLSyntaxError as e:
            if e.code == 5 and e.position[1] == 1:
                doc_end = e.position[0]
                end_char = find_nth(test_file, '\n', doc_end - 2)
                documents.append(lxml.etree.fromstring(test_file[:end_char]))
                if end_char == len(test_file):
                    finished = True
                test_file = test_file[end_char:]
            else:
                print e
                break
    return documents

def find_nth(doc, search, n=0):
    l = len(search)
    i = -l
    for c in xrange(n + 1):
        i = doc.find(search, i + l)
        if i < 0:
            break
    return i

find_nth代码在this问题中无耻地被盗。可能的是,在很多情况下,这段代码非常有用,但对于我来说,有大量略有不规则的文档(非常常见的学术数据),这是非常宝贵的。

答案 1 :(得分:0)

XML文档必须只有一个根元素;否则,它们不是well-formed,实际上不是XML。符合条件的解析器无法解析格式不正确的XML&#34;。

当您从多个文档构造单个XML文档时,只需将不同的根元素包装在单个根元素中。然后,您就可以使用标准解析器,例如lxml。