2011-07-27 31 views
12

刪除元素我有,我想尋找一些元素的XML文檔,如果它們與某些條件匹配 我想刪除這些搜索和與ElementTree的Python中

不過,我似乎無法能夠訪問該元素的父級,以便我可以刪除它

file = open('test.xml', "r") 
elem = ElementTree.parse(file) 

namespace = "{http://somens}" 

props = elem.findall('.//{0}prop'.format(namespace)) 
for prop in props: 
    type = prop.attrib.get('type', None) 
    if type == 'json': 
     value = json.loads(prop.attrib['value']) 
     if value['name'] == 'Page1.Button1': 
      #here I need to access the parent of prop 
      # in order to delete the prop 

有沒有辦法我可以做到這一點?

感謝

回答

13

您可以刪除與根據remove方法子元素。要刪除一個元素,你必須調用它的父母方法remove。不幸的是Element不提供其父母的引用,所以它是由你來跟蹤父/子關係(其中談到對你的使用elem.findall()

提議的解決方案看起來是這樣的:

root = elem.getroot() 
for child in root: 
    if child.name != "prop": 
     continue 
    if True:# TODO: do your check here! 
     root.remove(child) 

PS:不使用prop.attrib.get(),使用prop.get(),如解釋here

+0

我明白了。我也看看我讀過的lxml提供訪問元素的父項。無論如何,謝謝 – Thomas

+3

是的,這是正確的。 lxml提供了一個'ElementTree'實現,它具有比接口通常狀態更多的特性。 lxml中的'Element'類提供'getparent()'方法來獲得對父元素的引用。 – Constantinius

+2

如果子元素超過根元素的一個元素,該怎麼辦?如果它在不同的深度? – dwjohnston

2

您可以使用xpath選擇元素的父元素。

file = open('test.xml', "r") 
elem = ElementTree.parse(file) 

namespace = "{http://somens}" 

props = elem.findall('.//{0}prop'.format(namespace)) 
for prop in props: 
    type = prop.get('type', None) 
    if type == 'json': 
     value = json.loads(prop.attrib['value']) 
     if value['name'] == 'Page1.Button1': 
      # Get parent and remove this prop 
      parent = prop.find("..") 
      parent.remove(prop) 

http://docs.python.org/2/library/xml.etree.elementtree.html#supported-xpath-syntax

除了,如果你嘗試,這是行不通的:http://elmpowered.skawaii.net/?p=74

因此,你必須:

file = open('test.xml', "r") 
elem = ElementTree.parse(file) 

namespace = "{http://somens}" 
search = './/{0}prop'.format(namespace) 

# Use xpath to get all parents of props  
prop_parents = elem.findall(search + '/..') 
for parent in prop_parents: 
    # Still have to find and iterate through child props 
    for prop in parent.findall(search): 
     type = prop.get('type', None) 
     if type == 'json': 
      value = json.loads(prop.attrib['value']) 
      if value['name'] == 'Page1.Button1': 
       parent.remove(prop) 

這是兩個搜索和嵌套循環。內部搜索僅在已知包含道具作爲第一個孩子的元素上,但這可能並不意味着太多取決於您的模式。

1

利用每個孩子都必須有父母的事實,我將簡化@ kitsu.eb的例子。 f使用findall命令來獲取孩子和父母,他們的索引將是等效的。

file = open('test.xml', "r") 
    elem = ElementTree.parse(file) 

    namespace = "{http://somens}" 
    search = './/{0}prop'.format(namespace) 

    # Use xpath to get all parents of props  
    prop_parents = elem.findall(search + '/..') 

    props = elem.findall('.//{0}prop'.format(namespace)) 
    for prop in props: 
      type = prop.attrib.get('type', None) 
      if type == 'json': 
       value = json.loads(prop.attrib['value']) 
       if value['name'] == 'Page1.Button1': 
        #use the index of the current child to find 
        #its parent and remove the child 
        prop_parents[props.index[prop]].remove(prop) 
0

我知道這是一條古老的線索,但是當我試圖找出一個類似的任務時,這個問題一直在彈出。我不喜歡接受的答案有兩個原因:

1)它不處理多個嵌套級別的標籤。

2)如果在同一級別中多個xml標籤一個接一個被刪除,它將會中斷。由於每個元素都是Element._children的索引,所以在前向迭代時不應刪除。

我想一個更好的更靈活的解決方案是這樣的:

import xml.etree.ElementTree as et 
file = 'test.xml' 
tree = et.parse(file) 
root = tree.getroot() 

def iterator(parents, nested=False): 
    for child in reversed(parents): 
     if nested: 
      if len(child) >= 1: 
       iterator(child) 
     if True: # Add your entire condition here 
      parents.remove(child) 

iterator(root, nested=True) 

對於OP,這應該工作 - 但我沒有你正在使用,以測試它的完美數據。

import xml.etree.ElementTree as et 
file = 'test.xml' 
tree = et.parse(file) 

namespace = "{http://somens}" 
props = tree.findall('.//{0}prop'.format(namespace)) 

def iterator(parents, nested=False): 
    for child in reversed(parents): 
     if nested: 
      if len(child) >= 1: 
       iterator(child) 
     if prop.attrib.get('type') == 'json': 
      value = json.loads(prop.attrib['value']) 
      if value['name'] == 'Page1.Button1': 
       parents.remove(child) 

iterator(props, nested=True) 
0

我喜歡爲這種過濾使用XPath表達式。除非我另有所知,否則這樣的表達式必須應用於根級別,這意味着我不能只獲得一個父級並在該父級上應用相同的表達式。但是,在我看來,只要找不到任何根節點,就有一個適用於任何受支持的XPath的非常靈活的解決方案。它是這樣的:

root = elem.getroot() 
# Find all nodes matching the filter string (flt) 
nodes = root.findall(flt) 
while len(nodes): 
    # As long as there are nodes, there should be parents 
    # Get the first of all parents to the found nodes 
    parent = root.findall(flt+'/..')[0] 
    # Use this parent to remove the first node 
    parent.remove(nodes[0]) 
    # Find all remaining nodes 
    nodes = root.findall(flt)