access ElementTree node parent node
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}
Get parent element after using find method (xml.etree.ElementTree)
The xml.etree
API only supports a limited version of XPath. The xml.etree
docs for the ..
XPath expression state:
Selects the parent element. Returns None if the path attempts to
reach the ancestors of the start element (the element find was called
on).
Directly getting the parent element is not supported in the xml.etree
API. I would therefore recommend to use lxml
, where you can simply use getparent()
to get the parent element:
elm = root.find('.//Element[@elmid="1234"]')
elm.getparent()
lxml
also has a full XPath 1.0 implementation, so elem.xpath('..')
would work as well.
Python xml etree find parent node by text of child
Here is how I solved this, if anyone is interested in doing this stuff in xml instead of lxml (why ever).
According to suggestion from
http://effbot.org/zone/element.htm#accessing-parents
import xml.etree.ElementTree as et
tree = et.parse(my_xmlfile)
root = tree.getroot()
access = root.find('access')
# ... snip ...
def iterparent(tree):
for parent in tree.getiterator():
for child in parent:
yield parent, child
# users = list of user-names that need new_group added
# iter through tupel and find the username
# alter xml tree when found
for user in users:
print "processing user: %s" % user
for parent, child in iterparent(access):
if child.tag == "name" and child.text == user:
print "Name found: %s" % user
parent.append(et.fromstring('<group>%s</group>' % new_group))
After this et.dump(tree) shows that tree now contains the correctly altered user-subtree with another group tag added.
Note: I am not really sure why this works, I just expect that yield gives a reference to the tree and therefore altering the parent yield returned alters the original tree. My python knowledge is not good enough to be sure about this tho. I just know that it works for me this way.
Finding parent from child in XML using python
You need to traverse one level up
for elem in things.iterfind('thing/nodes/node[@id="1"]'):
# get parent of node - nodes
print elem.getparent()
# get grand parent of node - thing
print elem.getparent().getparent()
# now lets get the thing id
print elem.getparent().getparent().attrib.get('id')
remove parent node depending on the child element values
If I understand you correctly, this is what you need to do:
fruits = """[your code above]"""
import xml.etree.ElementTree as ET
tree = ET.fromstring(fruits)
targets = tree.findall('.//b')
for target in targets:
f_list= [t.text for t in target.findall('.//d')]
if not "banana" in f_list:
tree.remove(target)
print(ET.tostring(tree).decode())
#to write to file:
tree = ET.ElementTree(tree)
tree.write("test.xml", encoding="utf-8")
Output:
<a>
<header>
fruit
</header>
<b>
<fruitlist>
<d>banana</d>
</fruitlist>
<fruitlist>
<d>apple</d>
</fruitlist>
</b>
<b>
<fruitlist>
<d>banana</d>
</fruitlist>
</b>
</a>
How to find Parent Node for Nested Element XML Tag, Python 3.6
We can get parent from lxml:
import pandas as pd
import requests
from lxml import etree
from io import StringIO, BytesIO
Dimension_Id = 'RDS_DICT_REGIONS_NSO'
Language = '1033'
Request_URL = 'http://dataportal.ins.tn/WebApi/GetDimensionElements'
Method_Post_Body = "<QueryMessage lcid='" + Language + "'> <DataWhere> <DimensionId>" + Dimension_Id + "</DimensionId> </DataWhere> </QueryMessage>"
Post_Response = requests.post(Request_URL, data=Method_Post_Body, headers={'Content-type': 'text/xml'})
XRoot_P = etree.fromstring(Post_Response.content)
XML_List = []
XML_Structure_All = pd.DataFrame()
for Tag_1 in XRoot_P[1]:
for Child in Tag_1.iter():
if len(Child.getparent().attrib) > 0:
if 'CODE' in Child.getparent().attrib.keys():
Parent = Child.getparent().attrib['CODE']
elif 'C_CODE' in Child.getparent().attrib.keys():
Parent = Child.getparent().attrib['C_CODE']
elif 'KEY' in Child.getparent().attrib.keys():
Parent = Child.getparent().attrib['KEY']
else:
Parent = ''
if 'CODE' in Child.attrib.keys(): Col = 'CODE'
elif 'C_CODE' in Child.attrib.keys(): Col = 'C_CODE'
elif 'KEY' in Child.attrib.keys(): Col = 'KEY'
XML_Dict = {'CODE': Child.attrib[Col], 'Parent': Parent}
XML_List.append(XML_Dict)
XML_Dimension_Parent = pd.DataFrame(XML_List)
access ElementTree node parent node
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}
Get the entire parent tag's text in ElementTree
This is indeed a very awkward peculiarity of ElementTree. The gist is: if an element contains both text and child elements, and if a child element intervenes between different intermediate text nodes, the text after the child element is said to be this element's tail
instead of its text
.
In order to collect all text that is an immediate child or descendant of an element, you would need to access the text
and tail
of this element, and of all descendant elements.
>>> from lxml import etree
>>> s = '<p>This is the start of parent tag...<ref type="chlid1">child 1</ref>. blah1 blah1 blah1 <ref type="chlid2">child2</ref> blah2 blah2 blah2 </p>'
>>> root = etree.fromstring(s)
>>> child1, child2 = root.getchildren()
>>> root.text
'This is the start of parent tag...'
>>> child1.text, child1.tail
('child 1', '. blah1 blah1 blah1 ')
>>> child2.text, child2.tail
('child2', ' blah2 blah2 blah2 ')
As for a complete solution, I discovered that this answer is doing something very similar, that you can easily adapt to your usecase (by not printing the name of elements).
Edit: actually, the simplest solution by far, in my opinion, is to use itertext:
>>> ''.join(root.itertext())
'This is the start of parent tag...child 1. blah1 blah1 blah1 child2 blah2 blah2 blah2 '
Related Topics
How to Read the Rgb Value of a Given Pixel in Python
Remove and Replace Printed Items
Extract Images from PDF Without Resampling, in Python
What Exactly Is File.Flush() Doing
How to Ignore Deprecation Warnings in Python
How to Export Keras .H5 to Tensorflow .Pb
How to Get the Ip Address from a Nic (Network Interface Controller) in Python
How to Use Argsort in Descending Order
Python Numpy Valueerror: Operands Could Not Be Broadcast Together with Shapes
Python Multithreading Wait Till All Threads Finished
How to Plot Multiple Seaborn Jointplot in Subplot
Python' Is Not Recognized as an Internal or External Command
Why Does Python Code Use Len() Function Instead of a Length Method
How to Use Angularjs with the Jinja2 Template Engine
Decode Escaped Characters in Url