pythonxmlnamespaceselementtree

None type when parsing xml data in Python


I'd like to be able to parse some info from xml data while uses namespaces. I have been trying to read/follow steps in: https://docs.python.org/3/library/xml.etree.elementtree.html#parsing-xml-with-namespaces

This is a sample of how my xml looks like enter image description here

When I try going through xml tree using a nested for loop, it looks like my code can read the sub-elements successfully.

def toXML(s):
    xmlRoot= ET.fromstring(s)
    
    for child in xmlRoot:
        print(child.tag)
        for subchild in child:
            print(subchild.tag)
            for subchild in subchild:
                print(subchild.tag)

Output:

{http://www.w3.org/2003/05/soap-envelope}Body
{http://www.onvif.org/ver10/search/wsdl}GetRecordingSummaryResponse
{http://www.onvif.org/ver10/search/wsdl}Summary

Process finished with exit code 0

However, when I try to do this the nice way

    for child in xmlRoot.find('{http://www.onvif.org/ver10/search/wsdl}Summary'):
        NumberRecordings=child.find('{http://www.onvif.org/ver10/schema}NumberRecordings')
        print(NumberRecordings.text)

I get this error:

for child in xmlRoot.find('{http://www.onvif.org/ver10/search/wsdl}Summary'):
                 ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'NoneType' object is not iterable

Any idea why my child is None ?


Solution

  • You can find the text values with find(".//prefix:tagname", namespace). No need for interation.

    from lxml import etree
    
    xmlFile = "your_xml_file.xml"
    root = etree.parse(xmlFile).getroot()
    ns = root.nsmap
    
    dataFrom = root.find(".//tt:Data-From", ns).text
    print(dataFrom)
    
    dataUntil = root.find(".//tt:DataUntil", ns).text
    print(dataUntil)
    
    numberRecords = root.find(".//tt:NumberRecordings", ns).text
    print(numberRecords)
    

    Output:

    2025-03-19T15:22:10z
    2025-03-19T18:30:52Z
    1
    

    Or as an shorter alternative search for <tse:Summary> with find() and iterate over the childs:

    for elem in root.find(".//tse:Summary", ns):
        print(elem.text)