2014-10-05 41 views
0

我有以下格式的XML文件:的Python ElementTree的

<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文件,相应的输出文件将为:

<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> 

我该如何实现这一目标?

+1

你尝试过什么吗? – Beginner 2014-10-05 21:40:12

回答

0

公告中的元素的访问顺序,当你use iterparse - 这是一个深度优先搜索:

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) 

产量

('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') 

AHAH,你正在寻找的元素 - 嵌套最深的dir元素 - 是首先用start事件先访问并紧接着一个end事件(至少当我们只看dir El对此语句)。

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

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)) 

产量

<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