2011-07-27 9 views
12

yılında elementtree ile elemanını kaldırmak, ben mümkün gibi görünüyor olamaz ben oarama ve ben bazı elementlerin aramak istediğiniz bir XML belgesi var ve onlar bazı kriterleri eşleşirse ben</p> <p>Ancak bunları silmek istiyorum 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 

bunu yapabilirim bir yolu var mı silebilir böylece elemanın ebeveyni erişilir?

Teşekkür

cevap

13

Sen göre remove yöntemle alt öğelerini kaldırabilirsiniz. Bir elemanı kaldırmak için ebeveynleri remove yöntemini çağırmalısınız. Maalesef Element ebeveyninden bir başvuru sağlamaz, bu nedenle önerilen bir çözüm gibi görünebilir

(elem.findall() kullanımınız karşı konuşur) üst/alt ilişkileri takip etmek için size kalmış:

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

PS: here açıklandığı gibi, prop.get(), prop.get() kullanın, prop.attrib.get() kullanmayın.

+0

Anlıyorum. Ayrıca okuduğumdan öğenin ebeveyine erişim sağlayan lxml'ye bakıyorum. Yine de teşekkürler – Thomas

+3

Evet, bu doğru. lxml, arabirimin normalde belirttiğinden daha fazla özellik içeren bir 'ElementTree' uygulaması sağlar. Lxml'deki "Element" sınıfı, bir ana öğeye başvuru almak için getparent() yöntemini sağlar. – Constantinius

+2

Alt öğe, kökten daha derin bir öğeden fazlaysa ne olur? Ya değişken derinlikte ise? – dwjohnston

2

Bir öğenin üst öğeyi seçmek için xpath'i kullanabilirsiniz. hariç

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

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) 
Eğer bu işe yaramazsa o denerseniz: http://elmpowered.skawaii.net/?p=74

Bunun yerine sahip olmak:

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) 

İki arar ve iç içe geçmiş, döngü. İç arama sadece ilk çocuk olarak sahne içerdiği bilinen Elemanlar üzerinedir, ancak bu sizin şemanıza bağlı olarak çok fazla bir şey ifade etmeyebilir.

1

Her çocuğun bir ebeveyn olması gerektiği gerçeğini kullanarak, @ kitsu.eb örneğini basitleştireceğim. Çocukları ve ebeveynleri almak için findall komutunu kullanarak, endeksleri eşdeğer olacaktır.

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

Bu eski iplik olduğunu biliyorum ama bu da benzer bir görevi anlamaya çalışırken kadar haşhaş tuttu. İki nedenden dolayı kabul edilen cevabı beğenmedim:

1) Birden çok iç içe etiket düzeyini işlemez. 2) Birden fazla xml etiketi, birbiri ardına aynı seviyede silindiyse kesilir. Her öğe bir Element._children indeksi olduğundan, yinelemeyi yaparken silinmemelisiniz.

Daha iyi daha çok yönlü bir çözüm bu olduğunu düşünüyorum:

OP için
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) 

, bu çalışması gerekir - ama mükemmeldir olmadığını test etmek için kullanacağınız verileri yok.

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

bir filtreleme için bu tür bir XPath ifadesi kullanmak ister. Aksi halde bilmediğim sürece, bu tür bir ifade kök düzeyinde uygulanmalıdır, yani bir ebeveyne sahip olamıyorum ve aynı ifadeyi bu ebeveyne uygulayamam. Ancak, aranan düğümlerin hiçbiri kök olmadıkça, desteklenen herhangi bir XPath ile çalışması gereken güzel ve esnek bir çözüm olduğunu düşünüyorum. Bunun gibi bir şey gider:

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) 
İlgili konular