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

Python 使用lxml解析包含多个xml文档的文件,python,xml,lxml,Python,Xml,Lxml,因此,我假设这是一个非常典型的用例,但我在lxml文档中找不到任何关于此支持的内容。基本上,我有一个xml文件,它由许多不同的xml文档(特别是评论)组成。结构大致如下: <review> <!-- A bunch of metadata --> </review> <!-- The issue is here --> <review> <!-- A bunch of metadata --> </re

因此,我假设这是一个非常典型的用例,但我在
lxml
文档中找不到任何关于此支持的内容。基本上,我有一个xml文件,它由许多不同的xml文档(特别是评论)组成。结构大致如下:

<review>
    <!-- A bunch of metadata -->
</review>
<!-- The issue is here -->
<review>
    <!-- A bunch of metadata -->
</review>
但当我这样做时,我会得到一个错误:

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
函数吗?

XML文档必须有一个根元素;否则,它们不是,事实上也不是XML。一致解析器无法解析格式不正确的“XML”


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

因此,它有点粗糙,但应该相对健壮。这里有两个主要的消极因素:

  • 重复调用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
def fix_xml_列表(测试文件):
文件=[]
完成=错误
未完成时:
尝试:
lxml.etree.fromstring(测试文件)
除XmlSyntaxer错误为e外:
如果e.code==5和e.position[1]==1:
doc_end=e.位置[0]
end\u char=find\n(测试文件'\n',doc\u end-2)
documents.append(lxml.etree.fromstring(test\u文件[:end\u char]))
如果end\u char==len(测试文件):
完成=正确
测试文件=测试文件[结束字符:]
其他:
打印e
打破
归还文件
def查找(文档,搜索,n=0):
l=len(搜索)
i=-l
对于X范围内的c(n+1):
i=文件查找(搜索,i+l)
如果i<0:
打破
返回i

find\n
代码被无耻地从问号中偷走。这段代码可能在很多情况下都非常有用,但对于我来说,有大量稍微不规则的文档(学术数据中很常见),这是非常宝贵的。

完全合理的错误,事实上这是一个xml错误,应该照此处理。
我知道这是不正确的,但我不是在创建
xml
文件。它来自一个我无法控制的学术镜像,如果可能的话,我宁愿不必手动添加根元素。不管它是否在你的控制之外,或者你是否知道它是错误的,或者你是否有最好的意图。它不是XML,在您首次手动或编程修复它之前,您不能期望一致的XML解析器帮助您。对不起,如果这不是你想听到的,但这是它的方式。只需以编程方式在它们周围封装一个根,并将它们作为单个XML文档进行解析,或者将它们作为单独的XML文档进行解析,然后在单独解析后以编程方式组合结果。
将它们作为单独的XML文档进行解析,然后以编程方式组合结果。
:这就是我想要的,但似乎并没有一个简单的方法来实现这一目标,因为前进方向不同于标准。没有标准方法,因为您不在标准范围内操作,但我已经提供了两种简单的方法:(1)将单独的XML树包装在单个根元素中,或者(2)单独解析文档,提取您需要的内容,并根据您的特定需要组合结果。在这个层次上没有别的话可说。祝你好运。对不起,我不想打扰你,但就2而言,我不清楚你所说的“单独解析文档”是什么意思。你是说事先把文件分开吗?或者有没有一种方法可以自动做到这一点?
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