【问题标题】:Efficient removal of XML elements using Python使用 Python 高效删除 XML 元素
【发布时间】:2014-07-07 16:15:04
【问题描述】:

我正在尝试有效地编辑大小相当大的 XML 文件(通常为 100-500MB,但最大为 1GB),以删除所有出现的不包含具有给定值的属性的元素。我正在寻找在速度方面执行此操作的最有效方法,同时也不会将大量数据加载到内存中,因为这对于较大的文件来说是一个问题。

使用示例 XML,结构如下所示,其中父元素可以相互嵌套任意次数。

<root>
<parent>
    <child id="c1">
        <content />
    </child>
    <child id="c2">
        <content />
    </child>
</parent>
<parent>
    <parent>
        <child id="c3">
            <content />
        </child>
    </parent>
</parent>
</root>

使用上面的示例 XML,我试图删除 ID 不等于“c1”的所有子元素,以给出以下结果:

<root>
<parent>
    <child id="c1">
        <content />
    </child>
</parent>
<parent>
    <parent />
</parent>
</root>

目前我想出的最有效的方法是使用 cElementTree iterparse:

import xml.etree.cElementTree as ET

xml_source = 'xml file location'
xml_output = 'xml output file location'

context = ET.iterparse(xml_source, events=("start", "end"))
context = iter(context)

event, root = context.next()

for event, elem in context:
    if event == 'end' and elem.tag == 'child' and elem.attrib['id'] != 'c1':
        elem.clear()

ET.ElementTree(root).write(xml_output)

上面将在大约 10 秒内处理一个 100MB 大小的测试文件,有没有更有效的方法来实现这一点?

【问题讨论】:

    标签: python xml python-2.7 celementtree


    【解决方案1】:

    抱歉,我手头没有大的等效 xml 文件,因此您必须自己对这些建议进行基准测试... :-/

    1. context 有一个root 属性,因此您只能在(默认)“结束”事件上使用iterparse

      context = ET.iterparse(xml_source)
      
      for event, elem in context:
          if elem.tag == 'child' and elem.attrib['id'] != 'c1':
              elem.clear()
      
      ET.ElementTree(context.root).write(xml_output)    
      
    2. 使用lxml.etree 代替xml.etree

      import lxml.etree as ET
      
    3. lxml.etree.iterparse 有一个 tag 参数,仅对特定元素进行迭代:

      context = ET.iterparse(xml_source, tag='child')
      
      for event, elem in context:
          if elem.attrib['id'] != 'c1':
              elem.clear()
      
    4. 最后一个建议,但与速度无关。 elem.clear() 不会删除元素本身,只会清除其子元素、文本和尾部。所以你最终会得到空的 &lt;child/&gt; 元素:

      <root>
      <parent>
          <child id="c1">
              <content />
          </child>
          <child />
      </parent>
      <parent>
          <parent>
              <child />
          </parent>
      </parent>
      </root>
      

      使用 lxml 你可以使用它来代替elem.clear():

      for event, elem in context:
          if elem.attrib['id'] != 'c1':
              elem.getparent().remove(elem)
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多