Search code examples
pythonxmlparsingelementtree

How to iterate through Elementtree using namespaces


I have been trying to parse through an xml document using ElementTree in python to modify one of the elements, however I keep running into issues due to namespaces.

I can get all the tags from my xml document with

data = open('query-user-by-name.xml').read()
root = ET.fromstring(data)
for item in root.iter():
    print(item.tag)

which gives me:

{http://prism.evolveum.com/xml/ns/public/query-3}query
{http://prism.evolveum.com/xml/ns/public/query-3}filter
{http://prism.evolveum.com/xml/ns/public/query-3}equal
{http://prism.evolveum.com/xml/ns/public/query-3}matching
{http://prism.evolveum.com/xml/ns/public/query-3}path
{http://prism.evolveum.com/xml/ns/public/query-3}value

I have created a dictionary with a namespace:

namespaces = {'ns':'http://prism.evolveum.com/xml/ns/public/query-3'}

but when I try to find the element I am searching for with

data = open('query-user-by-name.xml').read()
root = ET.fromstring(data)
for item in root.iter('ns:value', namespaces):
    print(item.tag)

I get the error:

TypeError: iter() takes at most 2 arguments (3 given)

It seems like I am giving only two arguments and not three. What am I doing wrong to properly iterate through these elements using the namespace?

*Edit: Here is my query-all-users.xml file:

<query xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
        xmlns="http://prism.evolveum.com/xml/ns/public/query-3">
<filter>
        <equal>
        <matching>polyStringNorm</matching>
                <path>c:name</path>
                <value>lilpotter</value>
        </equal>
</filter>
</query>

Solution

  • As suggested by @gill Hamilton, you should use iterfind, but with a XPath expression, for instance: ".//ns:value".

    Here is a full example:

    import xml.etree.ElementTree as ET
    
    content = u"""\
    <query xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
            xmlns="http://prism.evolveum.com/xml/ns/public/query-3">
    <filter>
            <equal>
            <matching>polyStringNorm</matching>
                    <path>c:name</path>
                    <value>lilpotter</value>
            </equal>
    </filter>
    </query>"""
    
    root = ET.fromstring(content)
    
    NS = {'ns': 'http://prism.evolveum.com/xml/ns/public/query-3'}
    
    for item in root.iterfind(".//ns:value", NS):
        print(item.tag)
    
    # -> {http://prism.evolveum.com/xml/ns/public/query-3}value