2010-01-31 7 views
43

J'utilise le module Python ElementTree intégré. Il est facile d'accéder aux enfants, mais qu'en est-il des nœuds parents ou frères? - Est-ce que cela peut être fait efficacement sans traverser l'arbre entier?accéder au nœud parent du nœud ElementTree

+1

Voir http://stackoverflow.com/questions/374245/how-to-retrieve-the-parent-node-using- celementtree – kennytm

Répondre

33

Il n'existe aucun support direct sous la forme d'un attribut parent, mais vous pouvez utiliser les modèles décrits here pour obtenir l'effet souhaité. La seule ligne suivante est proposée (à partir du lien à afficher) pour créer un mappage enfant à des parents pour un arbre entier:

parent_map = dict((c, p) for p in tree.getiterator() for c in p) 
+0

Mise à jour de la syntaxe, 2017/python3 'parent_map = {(c, p) pour p dans l'arborescence.iter() pour c dans p} ' – gerardw

+1

Correction: ' parent_map = {c: p pour p dans root.iter() pour c dans p} ' – gerardw

14

Vinay's answer devrait fonctionner, mais pour Python 2.7+ et le 3.2+ il est recommandé:

parent_map = {c:p for p in tree.iter() for c in p} 

getiterator() est dépréciée en faveur de iter(), et il est agréable d'utiliser le nouveau constructeur de compréhension de la liste dict. Deuxièmement, lors de la construction d'un document XML, il est possible qu'un enfant ait plusieurs parents, bien que cela soit supprimé une fois que vous avez sérialisé le document. Si cela est important, vous pouvez essayer ceci:

parent_map = {} 
for p in tree.iter(): 
    for c in p: 
     if c in parent_map: 
      parent_map[c].append(p) 
      # Or raise, if you don't want to allow this. 
     else: 
      parent_map[c] = [p] 
      # Or parent_map[c] = p if you don't want to allow this 
+1

Que faire si vous n'avez pas accès à l'arborescence? Comme après un .find() – Brett

+1

je ne connais aucun moyen d'obtenir le nœud racine (et donc les parents/ancêtres) si vous n'avez pas enregistré une référence à celui-ci. Mais je ne comprends pas comment '.find()' a quelque chose à voir avec ça. – supergra

+0

Je viens d'utiliser '.find()' comme exemple de fonction qui retourne juste un élément – Brett

2

Une autre façon si vous voulez juste un seul parent de subElement et aussi le xpath de subElement.

parentElement = subElement.find(xpath+"/..") 
+2

Ne fonctionne pas pour moi, je reçois 'None' - même si j'utilise simplement 'subElement.find ('..')'. – damian

1

Si vous utilisez lxml, j'ai pu obtenir l'élément parent ce qui suit:

parent_node = next(child_node.iterancestors()) 

Cela déclenche une exception StopIteration si l'élément n'a pas d'ancêtres - alors soyez prêt pour attraper cela si vous pouvez rencontrer dans ce scénario.

4

Vous pouvez utiliser la notation xpath ... dans ElementTree.

<parent> 
    <child id="123">data1</child> 
</parent> 

xml.findall('.//child[@id="123"]...') 
>> [<Element 'parent'>] 
+0

Ceci est une solution fantastique, fonctionne avec find() aussi si vous savez qu'il n'y a qu'un seul élément que vous recherchez. Comme si: 'root.find (" .//*[@nom_test = 'generated_sql'] ... ")' – Bostone

3

Comme mentionné dans Get parent element after using find method (xml.etree.ElementTree) vous devez faire une recherche indirecte pour les parents. Ayant xml:

<a> 
<b> 
    <c>data</c> 
    <d>data</d>  
</b> 
</a> 

En supposant que vous avez créé l'élément etree dans la variable xml, vous pouvez utiliser:

In[1] parent = xml.find('.//c/..') 
In[2] child = parent.find('./c') 

Entraînant:

Out[1]: <Element 'b' at 0x00XXXXXX> 
Out[2]: <Element 'c' at 0x00XXXXXX> 

parent supérieur se trouve que: secondparent=xml.find('.//c/../..') étant <Element 'a' at 0x00XXXXXX>

1

Regardez le 19.7.2.2. section: Supported XPath syntax ...

parent de Recherche noeud en utilisant le chemin:

parent_node = node.find('..') 
+1

Avez-vous testé cela? Si vous étiez en mesure de le faire fonctionner, veuillez poster un exemple de code complet qui le démontre. Voir ce commentaire: https://stackoverflow.com/questions/2170610/access-elementtree-node-parent-node#comment44519212_21963494 – mzjn

+1

La documentation Python 3 dit: "Renvoie' None' si le chemin tente d'atteindre les ancêtres du début élément (l'élément 'find' a été appelé)." (https://docs.python.org/3/library/xml.etree.elementtree.html#supported-xpath-syntax). – mzjn

+0

Fonctionne pour moi. La réponse la meilleure et la plus cohérente. – ToTenMilan

Questions connexes