web-dev-qa-db-ja.com

ElementTreeノードの親ノードにアクセスします

私は組み込みのPython ElementTreeモジュールを使用しています。子にアクセスするのは簡単ですが、親または兄弟ノードについてはどうですか?-これはツリー全体をトラバースすることなく効率的に実行できますか?

55
hoju

parent属性の形式での直接的なサポートはありませんが、おそらく here で説明されているパターンを使用して、目的の効果を達成できます。ツリー全体の子から親へのマッピングを作成するには、次のワンライナーが推奨されます(リンク先の投稿から):

parent_map = dict((c, p) for p in tree.getiterator() for c in p)
44
Vinay Sajip

Vinayの答え は引き続き機能しますが、Python 2.7+および3.2+の場合、以下をお勧めします。

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

getiterator()iter()の代わりに非推奨となり、新しいdictリスト内包コンストラクターを使用するのは良いことです。

次に、XMLドキュメントの構築中に、子に複数の親が存在する可能性がありますが、ドキュメントをシリアル化すると削除されます。それが重要な場合は、これを試してみてください:

_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
_
20
supergra

ElementTreeでxpath ...表記を使用できます。

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

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

findメソッド(xml.etree.ElementTree)を使用した後に親要素を取得する で述べたように、親を間接的に検索する必要があります。 xmlを持つ:

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

Etree要素をxml変数に作成したと仮定すると、次を使用できます。

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

その結果:

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

上位の親は次のように見つかります:secondparent=xml.find('.//c/../..') being _<Element 'a' at 0x00XXXXXX>_

5
Vaasha

XPath '..'セレクターを使用して、3.5.3または3.6.1(少なくともOSXでは)の親ノードを取得することはできません。たとえば、対話モードでは:

import xml.etree.ElementTree as ET
root = ET.fromstring('<parent><child></child></parent>')
child = root.find('child')
parent = child.find('..') # retrieve the parent
parent is None # unexpected answer True

最後の答えはすべての希望を打ち破ります...

3
jlaurens

単一のsubElementの親だけが必要で、subElementのxpathもわかっている場合の別の方法。

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

ここに私の答えを貼り付けます https://stackoverflow.com/a/54943960/492336

私は同様の問題を抱えていたので、少し創造的になりました。自分自身で親子関係情報を追加することを妨げるものは何もありません。不要になったら後で削除できます。

def addParentInfo(et):
    for child in et:
        child.attrib['__my_parent__'] = et
        addParentInfo(child)

def stripParentInfo(et):
    for child in et:
        child.attrib.pop('__my_parent__', 'None')
        stripParentInfo(child)

def getParent(et):
    if '__my_parent__' in et.attrib:
        return et.attrib['__my_parent__']
    else:
        return None

# Example usage

tree = ...
addParentInfo(tree.getroot())
el = tree.findall(...)[0]
parent = getParent(el)
while parent:
    doSomethingWith(parent)
    parent = getParent(parent)
stripParentInfo(tree.getroot())
1
sashoalm

Lxmlを使用している場合、次のようにして親要素を取得できました。

parent_node = next(child_node.iterancestors())

要素に祖先がない場合、これによりStopIteration例外が発生します。そのシナリオに遭遇する可能性がある場合、それをキャッチする準備をしてください。

1
Shadow