使用 xml 树解析大型 python xml

Parse large python xml using xmltree

我有一个 python 脚本可以解析巨大的 xml 文件(最大的一个是 446 MB)

    try:
        parser = etree.XMLParser(encoding='utf-8')
        tree = etree.parse(os.path.join(srcDir, fileName), parser)
        root = tree.getroot()
    except Exception, e:
        print "Error parsing file "+str(fileName) + " Reason "+str(e.message)

    for child in root:
        if "PersonName" in child.tag:
            personName = child.text

这就是我的 xml 的样子 :

<?xml version="1.0" encoding="utf-8"?>
<MyRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" uuid="ertr" xmlns="http://www.example.org/yml/data/litsmlv2">
  <Aliases authority="OPP" xmlns="http://www.example.org/yml/data/commonv2">
     <Description>myData</Description>
     <Identifier>43hhjh87n4nm</Identifier>
  </Aliases>
  <RollNo uom="kPa">39979172.201167159</RollNo>
  <PersonName>Miracle Smith</PersonName>
  <Date>2017-06-02T01:10:32-05:00</Date>
....

我只想获取 PersonName 标签内容,仅此而已。其他标签我不关心。

遗憾的是我的文件很大,当我使用上面的代码时我总是收到这个错误:

Error parsing file 2eb6d894-0775-e611.xml Reason unknown error, line 1, column 310915857
Error parsing file 2ecc18b5-ef41-e711-80f.xml Reason Extra content at the end of the document, line 1, column 3428182
Error parsing file 2f0d6926-b602-e711-80f4-005.xml Reason Extra content at the end of the document, line 1, column 6162118
Error parsing file 2f12636b-b2f5-e611-80f3-00.xml Reason Extra content at the end of the document, line 1, column 8014679
Error parsing file 2f14e35a-d22b-4504-8866-.xml Reason Extra content at the end of the document, line 1, column 8411238
Error parsing file 2f50c2eb-55c6-e611-80f0-005056a.xml Reason Extra content at the end of the document, line 1, column 7636614
Error parsing file 3a1a3806-b6af-e611-80ef-00505.xml Reason Extra content at the end of the document, line 1, column 11032486

我的XML完全没问题,没有多余的内容。看来是大文件解析出错了。 我看过 iterparse() 但它似乎对我想要实现的目标来说很复杂,因为它提供了对整个 DOM 的解析,而我只想要根目录下的那个标签。另外,没有给我一个很好的样本来通过标签名称获得正确的值吗?

我应该使用正则表达式解析还是 grep /awk 方式来执行此操作?或者对我的代码进行任何调整都可以让我在这些大文件中获取人名?

更新: 试过这个示例,它似乎从 xml 打印整个世界,除了我的标签 ?

iterparse 是否从文件的底部到顶部读取?在那种情况下,需要很长时间才能到达顶部,即我的 PersonName 标签?我尝试更改下面的行以读取 end to start events=("end", "start") 并且它做了同样的事情 !!!

path = []
for event, elem in ET.iterparse('D:\mystage\2-80ea-005056.xml', events=("start", "end")):
    if event == 'start':
            path.append(elem.tag)
    elif event == 'end':
            # process the tag
            print elem.text  // prints whole world 
            if elem.tag == 'PersonName':
                print elem.text
            path.pop()

在这种情况下,Iterparse 并不难用。

temp.xml 是您问题中显示的文件,最后有一个 </MyRoot> 作为一行。

source = 视为样板,如果你愿意的话,它会逐个元素地解析 xml 文件和它的 returns 块,表明该块是否是'start' 元素或 'end' 并提供有关元素的信息。

在这种情况下,我们只需要考虑 'start' 个事件。我们观察 'PersonName' 标签并获取它们的文本。在 xml 文件中找到唯一的此类项目后,我们放弃处理。

>>> from xml.etree import ElementTree
>>> source = iter(ElementTree.iterparse('temp.xml', events=('start', 'end')))
>>> for an_event, an_element in source:
...     if an_event=='start' and an_element.tag.endswith('PersonName'):
...         an_element.text
...         break
... 
'Miracle Smith'

编辑,回复评论中的问题:

通常您不会这样做,因为 iterparse 旨在与大块 xml 一起使用。但是,通过将字符串包装在 StringIO 对象中,可以使用 iterparse.

对其进行处理
>>> from xml.etree import ElementTree
>>> from io import StringIO
>>> xml = StringIO('''\
... <?xml version="1.0" encoding="utf-8"?>
... <MyRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" uuid="ertr" xmlns="http://www.example.org/yml/data/litsmlv2">
...   <Aliases authority="OPP" xmlns="http://www.example.org/yml/data/commonv2">
...        <Description>myData</Description>
...             <Identifier>43hhjh87n4nm</Identifier>
...               </Aliases>
...                 <RollNo uom="kPa">39979172.201167159</RollNo>
...                   <PersonName>Miracle Smith</PersonName>
...                     <Date>2017-06-02T01:10:32-05:00</Date>
... </MyRoot>''')
>>> source = iter(ElementTree.iterparse(xml, events=('start', 'end')))
>>> for an_event, an_element in source:
...     if an_event=='start' and an_element.tag.endswith('PersonName'):
...         an_element.text
...         break
...     
'Miracle Smith'