Search code examples
pythonxmllxmlcarddav

LXML - .//{DAV:}response raises lxml.etree.XPathEvalError: Invalid expression


I'm trying to get all response tags by using:

.//{DAV:}response

tree = etree.fromstring(r.content)
   
for response in tree.xpath(".//{DAV:}response"):
    ...

The problem is that lxml returns this error:

lxml.etree.XPathEvalError: Invalid expression

I'm trying to avoid defining namespaces because every CardDav server has different namespaces (who knows why).

What's wrong with that expression?

XML:

 <?xml version='1.0' encoding='utf-8'?>
<multistatus xmlns="DAV:" xmlns:CR="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/">
    <response>
        <href>/admin/</href>
        <propstat>
            <prop>
                <resourcetype>
                    <principal/>
                    <collection/>
                </resourcetype>
            </prop>
            <status>HTTP/1.1 200 OK</status>
        </propstat>
        <propstat>
            <prop>
                <displayname/>
                <CS:getctag/>
            </prop>
            <status>HTTP/1.1 404 Not Found</status>
        </propstat>
    </response>
    <response>
        <href>/admin/yyyyyy/</href>
        <propstat>
            <prop>
                <resourcetype>
                    <CR:addressbook/>
                    <collection/>
                </resourcetype>
                <displayname>addressbook1</displayname>
                <CS:getctag>"xxxxx"</CS:getctag>
            </prop>
            <status>HTTP/1.1 200 OK</status>
        </propstat>
    </response>
</multistatus>

Solution

  • Consider assigning a temporary prefix for parsing nodes under that default namespace which should work for xpath and findall:

    tree = etree.fromstring(r.content)
    nsmp = {'doc': 'DAV:'}
    
    for response in tree.xpath(".//doc:response", namespaces=nsmp):
        ...
    
    for response in tree.findall(".//doc:response", namespaces=nsmp):
        ...