在ElementTree(1.3.0)Python中进行XML解析的有效方法

thc*_*and 5 python xml performance parsing lxml

我试图解析一个范围从(20MB-3GB)的巨大XML文件.文件是来自不同仪器的样本.所以,我正在做的是从文件中找到必要的元素信息并将它们插入数据库(Django).

我文件样本的一小部分.命名空间存在于所有文件中.文件的有趣特征是它们具有比文本更多的节点属性

<?xml VERSION="1.0" encoding="ISO-8859-1"?>
<mzML xmlns="http://psi.hupo.org/ms/mzml" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="http://psi.hupo.org/ms/mzml http://psidev.info/files/ms/mzML/xsd/mzML1.1.0.xsd" accession="plgs_example" version="1.1.0" id="urn:lsid:proteios.org:mzml.plgs_example">

    <instrumentConfiguration id="QTOF">
                    <cvParam cvRef="MS" accession="MS:1000189" name="Q-Tof ultima"/>
                    <componentList count="4">
                            <source order="1">
                                    <cvParam cvRef="MS" accession="MS:1000398" name="nanoelectrospray"/>
                            </source>
                            <analyzer order="2">
                                    <cvParam cvRef="MS" accession="MS:1000081" name="quadrupole"/>
                            </analyzer>
                            <analyzer order="3">
                                    <cvParam cvRef="MS" accession="MS:1000084" name="time-of-flight"/>
                            </analyzer>
                            <detector order="4">
                                    <cvParam cvRef="MS" accession="MS:1000114" name="microchannel plate detector"/>
                            </detector>
                    </componentList>
     </instrumentConfiguration>
Run Code Online (Sandbox Code Playgroud)

小但完整的文件在这里

所以我到目前为止所做的就是将findall用于所有感兴趣的元素.

import xml.etree.ElementTree as ET
tree=ET.parse('plgs_example.mzML')
root=tree.getroot()
NS="{http://psi.hupo.org/ms/mzml}"
s=tree.findall('.//{http://psi.hupo.org/ms/mzml}instrumentConfiguration')
for ins in range(len(s)):
    insattrib=s[ins].attrib
    # It will print out all the id attribute of instrument
    print insattrib["id"] 
Run Code Online (Sandbox Code Playgroud)

如何访问instrumentConfiguration(s)元素的所有子/孙?

s=tree.findall('.//{http://psi.hupo.org/ms/mzml}instrumentConfiguration')
Run Code Online (Sandbox Code Playgroud)

我想要的例子

InstrumentConfiguration
-----------------------
Id:QTOF
Parameter1: T-Tof ultima
source:nanoelectrospray
analyzer: quadrupole
analyzer: time-of-flight
detector: microchannel plate decector
Run Code Online (Sandbox Code Playgroud)

当命名空间存在时,是否有有效的方法来解析元素/子元素/子元素?或者我每次都必须使用find/findall来访问具有命名空间的树中的特定元素?这只是我必须解析更复杂的元素层次结构的一个小例子.

有什么建议!

编辑

没有得到正确答案所以必须再次编辑!

jfs*_*jfs 5

这是一个脚本,可以在几秒钟内(在我的机器上)解析一百万个<instrumentConfiguration/>元素(967MB文件),40而不会占​​用大量内存。

吞吐量为24MB/s。该cElementTree page (2005)报告47MB/s

#!/usr/bin/env python
from itertools import imap, islice, izip
from operator  import itemgetter
from xml.etree import cElementTree as etree

def parsexml(filename):
    it = imap(itemgetter(1),
              iter(etree.iterparse(filename, events=('start',))))
    root = next(it) # get root element
    for elem in it:
        if elem.tag == '{http://psi.hupo.org/ms/mzml}instrumentConfiguration':
            values = [('Id', elem.get('id')),
                      ('Parameter1', next(it).get('name'))] # cvParam
            componentList_count = int(next(it).get('count'))
            for parent, child in islice(izip(it, it), componentList_count):
                key = parent.tag.partition('}')[2]
                value = child.get('name')
                assert child.tag.endswith('cvParam')
                values.append((key, value))
            yield values
            root.clear() # preserve memory

def print_values(it):
    for line in (': '.join(val) for conf in it for val in conf):
        print(line)

print_values(parsexml(filename))
Run Code Online (Sandbox Code Playgroud)

输出量

$ /usr/bin/time python parse_mxml.py
Id: QTOF
Parameter1: Q-Tof ultima
source: nanoelectrospray
analyzer: quadrupole
analyzer: time-of-flight
detector: microchannel plate detector
38.51user 1.16system 0:40.09elapsed 98%CPU (0avgtext+0avgdata 23360maxresident)k
1984784inputs+0outputs (2major+1634minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

注意:该代码易碎,它假定<instrumentConfiguration/>are <cvParam/>和的前两个子代,<componentList/>并且所有值都可用作标记名或属性。

表现上

在这种情况下,ElementTree 1.3比cElementTree 1.0.6慢约6倍。

如果您替换为root.clear()elem.clear()则代码速度将提高约10%,但内存将增加约10倍。lxml.etreeelem.clear()变体一起使用时,性能与之相同,cElementTree但消耗的内存(500MB)是它的20(root.clear())/ 2(elem.clear())倍。