首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python ElementTree

Python ElementTree
EN

Stack Overflow用户
提问于 2014-10-06 05:24:00
回答 1查看 111关注 0票数 0

我有一个XML文件,格式如下:

代码语言:javascript
复制
<dir name="A">
    <dir name="B">
        <file name="foo.txt"/>
    </dir>
    <dir name="C">
        <dir name="D">
            <file name="bar.txt"/>
        </dir>
    </dir>
</dir>
<dir name="E">
    <file name="bat.txt"/>
    <file name="cat.txt"/>
</dir>
<dir name="F">
    <dir name="G">
        <file name="dog.txt"/>
        <file name="rabbit.txt"/>
    </dir>
</dir>

我想使用python ElementTree模块来删除任何包含元素的元素。也就是说,我希望获得XML文件的内部元素(其中不包含另一个元素的元素),以及它们的所有子元素。我希望将任何这样的元素设置为外层。例如,对于上面的XML文件,对应的输出文件为:

代码语言:javascript
复制
<dir name="B">
    <file name="foo.txt"/>
</dir>
<dir name="D">
    <file name="bar.txt"/>
</dir>
<dir name="E">
    <file name="bat.txt"/>
    <file name="cat.txt"/>
</dir>
<dir name="G">
    <file name="dog.txt"/>
    <file name="rabbit.txt"/>
</dir>

我如何才能做到这一点?

EN

回答 1

Stack Overflow用户

发布于 2014-10-06 06:01:15

注意use iterparse时访问元素的顺序--这是深度优先搜索:

代码语言:javascript
复制
import xml.etree.ElementTree as ET

with open('data', 'rb') as f:
    context = ET.iterparse(f, events=('start', 'end'))
    for event, elem in context:
        if elem.tag == 'dir':
            name = elem.get('name')
            print(event, name)

收益率

代码语言:javascript
复制
('start', 'A')
('start', 'B')     <-- ('start', 'B') is follow immediately by ('end', 'B')
('end', 'B')       <--
('start', 'C')
('start', 'D')     <-- start is follow immediately by end
('end', 'D')
('end', 'C')
('end', 'A')
('start', 'E')     <-- start is follow immediately by end
('end', 'E')
('start', 'F')
('start', 'G')     <-- start is follow immediately by end
('end', 'G')
('end', 'F')

啊哈,您正在寻找的元素--嵌套最深的dir元素--是那些iterparse首先使用start事件访问,然后紧接着使用end事件访问的元素(至少当我们只查看dir元素时是这样的)。

因此,使用这个想法,我们可以将这些元素收集到一个新的root元素中,以获得所需的XML:

代码语言:javascript
复制
root = ET.Element('root')
previous_name = None
with open('data', 'rb') as f:
    context = ET.iterparse(f, events=('start', 'end'))
    for event, elem in context:
        if elem.tag == 'dir':
            name = elem.get('name')
            if event == 'start':
                previous_name = name
            elif previous_name == name:
                root.append(elem)
print(ET.tostring(root))

收益率

代码语言:javascript
复制
<root><dir name="B">
        <file name="foo.txt" />
    </dir>
    <dir name="D">
            <file name="bar.txt" />
        </dir>
    <dir name="E">
    <file name="bat.txt" />
    <file name="cat.txt" />
</dir>
<dir name="G">
        <file name="dog.txt" />
        <file name="rabbit.txt" />
    </dir>
</root>

注意,在iterparse访问任何元素之后,上面的iterparse代码不会清除任何元素。如果XML很大,在不清除任何元素的情况下使用iterparse可能会占用太多内存。在这种情况下,为了性能和更好的内存管理,我会使用lxml和fast_iter

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26207372

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档