組み込みのPythonElementTreeモジュールを使用しています。子にアクセスするのは簡単ですが、親ノードまたは兄弟ノードはどうでしょうか。-これは、ツリー全体を横断することなく効率的に実行できますか?
10 に答える
属性の形で直接サポートするparent
ことはできませんが、ここで説明するパターンを使用して、目的の効果を実現できます。次のワンライナーが提案されています(リンク先の投稿からPython 3.8に更新)。メソッドを使用して、ツリー全体の子から親へのマッピングを作成しますxml.etree.ElementTree.Element.iter
。
parent_map = {c: p for p in tree.iter() 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'>]
検索メソッド(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/../..')
。<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
最後の答えはすべての希望を破ります...
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())
から回答を得ました
https://towardsdatascience.com/processing-xml-in-python-elementtree-c8992941efd2
ヒント:XPath内で「...」を使用して、現在の要素の親要素を返します。
for object_book in root.findall('.//*[@name="The Hunger Games"]...'):
print(object_book)
lxmlを使用している場合、次の親要素を取得できました。
parent_node = next(child_node.iterancestors())
StopIteration
要素に祖先がない場合、これにより例外が発生します。そのため、そのシナリオに遭遇する可能性がある場合は、それをキャッチする準備をしてください。
単一のsubElementの親が必要で、subElementのxpathもわかっている場合の別の方法。
parentElement = subElement.find(xpath+"/..")