使用iterparse'失败'孩子的XML解析器

时间:2014-09-09 18:45:16

标签: xml large-files children iterparse

感谢您对以下方面的帮助:我需要阅读一个大型XML文件并将其转换为CSV格式。

我有两个假设要做同样的函数,只有一个(function1)使用iterparse(因为我需要处理大约2GB文件)而另一个函数没有(函数2)。

Function2对于相同的XML文件(但最多150 MB)非常有效,并且在该大小之后由于内存而失败。

我遇到的问题是,尽管代码(对于function1)没有出错,但它会丢失一些孩子(这是一个很大的问题!)。另一方面,功能2读取所有孩子,并且没有松散的'或任何失败。

问:你能否在function1的代码中看到为什么有些孩子会丢失(或者没有正确阅读或被忽略)?

注1:我需要准备好发送50 KB XML样本。
注2:变量' nchil_count'只计算孩子的数量。

CODE(function1):

def function1 ():
    # This function uses Iterparse
    # Doesn't give errors but looses some children. Why?
    # prints output to csv file, WCEL.csv

    from xml.etree.cElementTree import iterparse

    fname = "C:\Leonardo\Input data\Xml input data\NetactFiles\Netact_3g_rnc11_t1.xml"
    # ELEMENT_LIST = ["WCEL"]

    # Delete contents from exit file
    open("C:\Leonardo\Input data\Xml input data\WCEL.csv", 'w').close()

    # Open exit file
    with open("C:\Leonardo\Input data\Xml input data\WCEL.csv", "a") as exit_file:

        with open(fname) as xml_doc:
            context = iterparse(xml_doc, events=("start", "end"))
            context = iter(context)
            event, root = context.next()

            for event, elem in context:

                if event == "start" and elem.tag == "{raml20.xsd}managedObject":
                # if event == "start":
                    if elem.get('class') == 'WCEL':
                        print elem.attrib
                        # print elem.tag

                        element = elem.getchildren()
                        nchil_count = 0

                        for child in element:
                            if child.tag == "{raml20.xsd}p":
                                nchil_count = nchil_count + 1
                                # print child.tag
                                # print child.attrib
                                val = child.text
                                # print val
                                val = str (val)
                                exit_file.write(val + ",")

                        exit_file.write('\n')
                        print nchil_count

                elif event == "end" and elem.tag == "{raml20.xsd}managedObject":
                    # Clear Memory
                    root.clear()

    xml_doc.close()
    exit_file.close()

    return ()

代码(功能2):

def function2 (xmlFile):
    # Using Element Tree
    # Successful
    # Works well with files of 150 MB, like an XML (RAML) RNC export from Netact (1 RNC only)
    # It fails with huge files due to Memory

    import xml.etree.cElementTree as etree
    import shutil

    with open("C:\Leonardo\Input data\Xml input data\WCEL.csv", "a") as exit_file:

        # Populate the values per cell:

        tree = etree.parse(xmlFile)
        for value in tree.getiterator(tag='{raml20.xsd}managedObject'):
            if value.get('class') == 'WCEL':
                print value.attrib

                element = value.getchildren()
                nchil_count = 0

                for child in element:
                    if child.tag == "{raml20.xsd}p":
                        nchil_count = nchil_count + 1
                        # print child.tag
                        # print child.attrib
                        val = child.text
                        # print val

                        val = str (val)
                        exit_file.write(val + ",")

                exit_file.write('\n')
                print nchil_count

    exit_file.close() ## File closing after writing.

    return ()

1 个答案:

答案 0 :(得分:1)

我有类似的问题。但是有一些重要的区别:

  • 我使用的是lxml.etree,而不是xml.etree(来自http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml的Windows的lxml-3.4.2-cp34-none-win32.whl的二进制版本)
  • 我将iterparse用于活动结束事件的特定元素
  • 然后我使用xpath()方法
  • 向下钻取这个元素

但结果是等价的:一些节点被忽略(丢失)。文件中没有任何内容可以解释原因。对于给定的文件 - 相同的节点。但是,当你只进行技术更改(格式为xmllint) - 其他节点丢失时。

我重新组织了代码(没有xpath(),iterparse没有tag参数,'start'和'end'事件,用element.tag属性值控制进程)并发现 SOMETIMES (我不知道什么时候)过程“忘记”默认的NAMESPACE 。我的意思是,在大多数情况下,element.tag的值是“{namespace uri} tag_name”,但在大约2%的情况下 - 只是“tag_name”。这就是xpath()找不到它们的原因。

我知道文件中的所有内容都来自一个默认命名空间,所以我可以自己添加“{namespace uri}”,并正确处理文件。

如果在主标记中明确声明了名称空间前缀并在所有其他标记中使用,则没有问题。

在解析大型XML文件时,这看起来像是一个错误 - 如果你在xml.etree中有相同的效果,可能不会在lxml中?