使用xmltree解析大型python xml

时间:2017-09-11 22:43:36

标签: python xml grep lxml elementtree

我有一个解析大型xml文件的python脚本(最大的一个是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标签?我尝试更改下面的行以读取结束以开始事件=(&#34;结束&#34;,&#34;开始&#34;)并且它做同样的事情!!!

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()

1 个答案:

答案 0 :(得分:2)

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

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

source =视为boeplace,如果愿意的话,解析xml文件并逐个元素地返回它的块,指示块是元素的'开头'还是'结束' '并提供有关该元素的信息。

在这种情况下,我们只需考虑'开始'事件。我们会查看“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'