Home > database >  How to get list of subelements that are only one level deep from Python3 xml.etree.Element?
How to get list of subelements that are only one level deep from Python3 xml.etree.Element?

Time:11-13

If I have a Python3 xml.etree.Element (doc), is it possible to get a list (or iterable, or whatever) of child elements to that Element, but only one level deep? If so, how can I do this?

(Note: it appears the xml.etree.Element library is essentially the same for the version of Python I'm using (3.6.8) and the latest version (3.11).)


For example, say I have this xml:

<?xml version="1.0" encoding="UTF-8"?>
<Document>
  <name>myName</name>
  <SomeLevel1Element>
    <SomeLevel2Element>foo</SomeLevel2Element>
  </SomeLevel1Element>
  <SomeLevel1Element>
    <SomeLevel2Element>bar</SomeLevel2Element>
  </SomeLevel1Element>
  <AnotherLevel1Element>
  </AnotherLevel1Element>
</Document>

I want to do something like:

import xml.etree.ElementTree as ET
tree = ET.parse(PATH_TO_XML_FILE)
root = tree.getroot()
direct_children_of_root = <something>
for child in direct_children_of_root:
  print(child)

"""
<Element 'name' at 0x123abc>
<Element 'SomeLevel1Element' at 0x123bbc>
<Element 'SomeLevel1Element' at 0x123cbc>
<Element 'AnotherLevel1Element' at 0x123dbc>
"""

I cannot use findall(), find(), findtext(), since I may not know the amount or kinds of child elements of root.


I cannot use iter(), since that method appears to give all children of all children elements.

For example, using the same xml as above:

import xml.etree.ElementTree as ET
tree = ET.parse(PATH_TO_XML_FILE)
root = tree.getroot()
elems = root.iter()
for e in elems:
  print(e)

"""
<Element 'Document' at 0x123abc>
<Element 'name' at 0x123bbc>
<Element 'SomeLevel1Element' at 0x123cbc>
<Element 'SomeLevel2Element' at 0x123dbc>
<Element 'SomeLevel1Element' at 0x123ebc>
<Element 'SomeLevel2Element' at 0x123fbc>
<Element 'AnotherLevel1Element' at 0x124abc>
"""

CodePudding user response:

xml.etree.ElementTree has limited support for Xpath.
Using lxml instead

>>> from lxml import etree
>>> doc = etree.parse('tmp.xml')
>>> parentName = doc.getroot().tag
>>> level1 = doc.xpath(f'//*[parent::{parentName}]')
>>> for e in level1:
...     print(e.tag)
... 
name
SomeLevel1Element
SomeLevel1Element
AnotherLevel1Element

If xml.etree.ElementTree is required

>>> level1 = root.findall('.')[0].findall('./*')
>>> for e in level1:
...     print(e.tag)
... 
name
SomeLevel1Element
SomeLevel1Element
AnotherLevel1Element

CodePudding user response:

list(root) returns a list with the children of root.

direct_children_of_root = list(root)
for child in direct_children_of_root:
    print(child)

Even simpler is to just iterate over root directly.

for child in root:
    print(child)
  • Related