私は組み込みのPython ElementTreeモジュールを使用しています。子にアクセスするのは簡単ですが、親または兄弟ノードについてはどうですか?-これはツリー全体をトラバースすることなく効率的に実行できますか?
parent
属性の形式での直接的なサポートはありませんが、おそらく here で説明されているパターンを使用して、目的の効果を達成できます。ツリー全体の子から親へのマッピングを作成するには、次のワンライナーが推奨されます(リンク先の投稿から):
parent_map = dict((c, p) for p in tree.getiterator() for c in p)
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
_
ElementTreeでxpath ...
表記を使用できます。
<parent>
<child id="123">data1</child>
</parent>
xml.findall('.//child[@id="123"]...')
>> [<Element 'parent'>]
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>
_
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
最後の答えはすべての希望を打ち破ります...
単一のsubElementの親だけが必要で、subElementのxpathもわかっている場合の別の方法。
parentElement = subElement.find(xpath+"/..")
ここに私の答えを貼り付けます 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())
Lxmlを使用している場合、次のようにして親要素を取得できました。
parent_node = next(child_node.iterancestors())
要素に祖先がない場合、これによりStopIteration
例外が発生します。そのシナリオに遭遇する可能性がある場合、それをキャッチする準備をしてください。