使用Python高效去除XML元素
我正在尝试高效地编辑比较大的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)
使用这种方法,处理一个100MB的测试文件大约需要10秒钟,请问有没有更有效的方法可以实现这个目标?
1 个回答
1
抱歉,我手头没有一个大的等效xml文件,所以你得自己测试这些建议… :-/
这个
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)
用
lxml.etree
替代xml.etree
:import lxml.etree as ET
lxml.etree.iterparse
有一个tag
参数,可以只遍历特定的元素:context = ET.iterparse(xml_source, tag='child') for event, elem in context: if elem.attrib['id'] != 'c1': elem.clear()
最后一个建议,虽然不是关于速度的。
elem.clear()
并不会删除元素本身,而只是清空它的子元素、文本和尾部内容。所以你会得到空的<child/>
元素:<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)