【问题标题】:Parsing XML file using parseString from xml.dom.minidom has poor efficiency?使用 xml.dom.minidom 中的 parseString 解析 XML 文件效率低下?
【发布时间】:2015-02-10 16:51:29
【问题描述】:

我正在尝试使用 Python 2.7 解析 XML 文件。 XML 文件的大小为 370+ MB,包含 6,541,000 行。

XML 文件由以下 300K 块组成:

<Tag:Member>
    <fileID id = '123456789'>
    <miscTag> 123 </miscTag>
    <miscTag2> 456 </miscTag2>
    <DateTag> 2008-02-02 </DateTag>
    <Tag2:descriptiveTerm>Keyword_1</Tag2:descriptiveTerm>
    <miscTag3>6.330016</miscTag3>
    <historyTag>
        <DateTag>2001-04-16</DateTag>
        <reasonTag>Refresh</reasonTag>
    </historyTag>
    <Tag3:make>Keyword_2</Tag3:make>
    <miscTag4>
            <miscTag5>
                <Tag4:coordinates>6.090,6.000 5.490,4.300 6.090,6.000 </Tag4:coordinates>
            </miscTag5>
        </miscTag4>
</Tag:Member>

我使用了以下代码:

from xml.dom.minidom import parseString

def XMLParser(filePath):    
    """ ===== Load XML File into Memory ===== """
    datafile = open(filePath)
    data = datafile.read()
    datafile.close()
    dom = parseString(data)    

    length = len(dom.getElementsByTagName("Tag:Member"))


    counter = 0
    while counter < length:
        """ ===== Extract Descriptive Term ===== """
        contentString = dom.getElementsByTagName("Tag2:descriptiveTerm")[counter].toxml()

        laterpart = contentString.split("Tag2:descriptiveTerm>", 1)[1]

        descriptiveTerm = laterpart.split("</Tag2:descriptiveTerm>", 1)[0]    


        if descriptiveGroup == "Keyword_1":
            """ ===== Extract Make ===== """
            contentString = dom.getElementsByTagName("Tag3:make")[counter].toxml()

            laterpart = contentString.split("<Tag3:make>", 1)[1]

            make = laterpart.split("</Tag3:make>", 1)[0]



            if descriptiveTerm == "Keyword_1" and make == "Keyword_2":
                """ ===== Extract ID ===== """        
                contentString = dom.getElementsByTagName("Tag:Member")[counter].toxml()

                laterpart = contentString.split("id=\"", 1)[1]

                laterpart = laterpart.split("Tag", 1)[1]

                IDString = laterpart.split("\">", 1)[0]



                """ ===== Extract Coordinates ===== """
                contentString = dom.getElementsByTagName("Tag:Member")[counter].toxml()

                laterpart = contentString.split("coordinates>", 1)[1]

                coordString = laterpart.split(" </Tag4:coordinates>", 1)[0]            


        counter += 1

所以,我运行了这个,发现它需要大约 27GB 的内存,并且解析上述每个块需要超过 20 秒。所以解析这个文件需要2个月!

我想我写了一些效率低下的代码。谁能帮我改进一下?

非常感谢。

【问题讨论】:

  • 从 DOM 转换回 XML 确实是不必要且低效的,并且使用字符串拆分来导航 XML 是非常可怕的。坦率地说,人们通常根本不再使用 minidom,除非他们试图运行为更旧版本的 Python 编写的代码,所以建议的要点是“不要那样做”。 :)
  • 我强烈(强烈!)建议使用基于 libxml2 的现代库; lxml 符合要求,尽管 cElementTree 也是可行的。并且永远不要在语法元素上使用字符串拆分来解析您的 XML。
  • 实际上,对于这种大小的文件,流式解析器可能是提高效率的更好选择。
  • 顺便说一句,Tag1Tag2 不是标签,而是命名空间,它们需要在父文档中的某处声明 xmlns 才能成为有效语法,而您在示例中没有给出。

标签: python xml performance minidom


【解决方案1】:

对于这种大小的文件,正确的方法是流式解析器(SAX 样式,而不是 DOM 样式,因此 minidom 完全不合适)。请参阅this answer 以了解有关以节省内存的方式使用lxml.iterparse(一种最近/现代的流式解析器,它使用libxml2——一种用C 编写的快速高效的XML 解析库——在其后端)的注释,或@987654322 @。

一般来说——当你看到与一个成员相关联的元素时,你应该在内存中建立那个成员,当你看到一个与标签末尾相关联的事件时,你会发出或处理建立的 in-记忆内容并开始一个新的内容。

【讨论】:

    猜你喜欢
    • 2015-01-03
    • 1970-01-01
    • 2012-08-17
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 2015-11-04
    • 2017-04-05
    • 1970-01-01
    相关资源
    最近更新 更多