1

I have an xml string that I need to parse in python that looks like this:

 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
     <s:Body>
         <PostLoadsResponse xmlns="http://webservices.truckstop.com/v11">
             <PostLoadsResult xmlns:a="http://schemas.datacontract.org/2004/07/WebServices.Objects" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                 <Errors xmlns="http://schemas.datacontract.org/2004/07/WebServices">
                    <Error>
                         <ErrorMessage>Invalid Location</ErrorMessage>
                    </Error>
                </Errors>
            </PostLoadsResult>
        </PostLoadsResponse>
    </s:Body>
</s:Envelope>'

I'm having trouble using xmltree to get to the error message of this tree without something like:

import xml.etree.ElementTree as ET
ET.fromstring(text).findall('{http://schemas.xmlsoap.org/soap/envelope/}Body')[0].getchildren()[0].getchildren()[0].getchildren()
Rob
  • 3,333
  • 5
  • 28
  • 71

3 Answers3

5

You need to handle namespaces and you can do it with xml.etree.ElementTree:

tree = ET.fromstring(data)

namespaces = {
    's': 'http://schemas.xmlsoap.org/soap/envelope/', 
    'd': "http://schemas.datacontract.org/2004/07/WebServices"
}
print(tree.find(".//d:ErrorMessage", namespaces=namespaces).text)

Prints Invalid Location.

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
2

Using the partial XPath support:

ET.fromstring(text).find('.//{http://schemas.datacontract.org/2004/07/WebServices}ErrorMessage')

That will instruct it to find the first element named ErrorMessage with namespace http://schemas.datacontract.org/2004/07/WebServices at any depth.

However, it may be faster to use something like

ET.fromstring(text).find('{http://schemas.xmlsoap.org/soap/envelope/}Body').find('{http://webservices.truckstop.com/v11}PostLoadsResponse').find('{http://webservices.truckstop.com/v11}PostLoadsResult').find('{http://schemas.datacontract.org/2004/07/WebServices}Errors').find('{http://schemas.datacontract.org/2004/07/WebServices}Error').find('{http://schemas.datacontract.org/2004/07/WebServices}ErrorMessage'

If you know your message will always contain those elements.

Dan Field
  • 20,885
  • 5
  • 55
  • 71
2

You can use the getiterator method on the tree to iterate through the items in it. You can check the tag on each item to see if it's the right one.

>>> err = [node.text for node in tree.getiterator() if node.tag.endswith('ErrorMessage')]
>>> err
['Invalid Location']
Brad Campbell
  • 2,969
  • 2
  • 23
  • 21