access ElementTree node parent node
I am using the builtin Python ElementTree module. It is straightforward to access children, but what about parent or sibling nodes? - can this be done efficiently without traversing the entire tree?
There's no direct support in the form of a parent
attribute, but you can perhaps use the patterns described here to achieve the desired effect. The following one-liner is suggested (updated from the linked-to post to Python 3.8) to create a child-to-parent mapping for a whole tree, using the method xml.etree.ElementTree.Element.iter
:
parent_map = {c: p for p in tree.iter() for c in p}
Vinay's answer should still work, but for Python 2.7+ and 3.2+ the following is recommended:
parent_map = {c:p for p in tree.iter() for c in p}
getiterator()
is deprecated in favor of iter()
, and it's nice to use the new dict
list comprehension constructor.
Secondly, while constructing an XML document, it is possible that a child will have multiple parents, although this gets removed once you serialize the document. If that matters, you might try this:
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
You can use xpath ...
notation in ElementTree.
<parent>
<child id="123">data1</child>
</parent>
xml.findall('.//child[@id="123"]...')
>> [<Element 'parent'>]
As mentioned in Get parent element after using find method (xml.etree.ElementTree) you would have to do an indirect search for parent. Having xml:
<a>
<b>
<c>data</c>
<d>data</d>
</b>
</a>
Assuming you have created etree element into xml
variable, you can use:
In[1] parent = xml.find('.//c/..')
In[2] child = parent.find('./c')
Resulting in:
Out[1]: <Element 'b' at 0x00XXXXXX>
Out[2]: <Element 'c' at 0x00XXXXXX>
Higher parent would be found as:secondparent=xml.find('.//c/../..')
being <Element 'a' at 0x00XXXXXX>