8

My XML string is -

xmlData = """<SMSResponse xmlns="http://example.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
             <Cancelled>false</Cancelled>
             <MessageID>00000000-0000-0000-0000-000000000000</MessageID>  
             <Queued>false</Queued>
             <SMSError>NoError</SMSError>
             <SMSIncomingMessages i:nil="true"/>
             <Sent>false</Sent>
             <SentDateTime>0001-01-01T00:00:00</SentDateTime>
             </SMSResponse>"""

I am trying to parse and get the values of tags - Cancelled, MessageId, SMSError, etc. I am using python's Elementtree library. So far, I have tried things like -

root = ET.fromstring(xmlData)
print root.find('Sent')  // gives None
for child in root:
    print chil.find('MessageId') // also gives None

Although, I am able to print the tags with -

for child in root:
    print child.tag
    //child.tag for the tag Cancelled is - {http://example.com}Cancelled

and their respective values with -

for child in root:
    print child.text

How do I get something like -

print child.Queued // will print false

Like in PHP we can access them with the root -

$xml = simplexml_load_string($data);
$status = $xml->SMSError;

4 Answers 4

8

Your document has a namespace on it, you need to include the namespace when searching:

root = ET.fromstring(xmlData)
print root.find('{http://example.com}Sent',)
print root.find('{http://example.com}MessageID')

output:

<Element '{http://example.com}Sent' at 0x1043e0690>
<Element '{http://example.com}MessageID' at 0x1043e0350>

The find() and findall() methods also take a namespace map; you can search for a arbitrary prefix, and the prefix will be looked up in that map, to save typing:

nsmap = {'n': 'http://example.com'}
print root.find('n:Sent', namespaces=nsmap)
print root.find('n:MessageID', namespaces=nsmap)
Sign up to request clarification or add additional context in comments.

9 Comments

so basically I am gonna have to specify "{example.com}" every time I want to access the text of a tag?
@HussainTamboli: There is also a namespaces=mapping argument to find and findall but that appears to be useless when there is a default namespace. lxml handles this all a lot better.
See @eclaird's answer. I think you were trying to do the same. +1
It still prints None with nsmap. I think there is something wrong with nsmap.
@HussainTamboli: I get output for your sample XML. Make sure you spelled the tag name correctly (MessageID and not MessageId).
|
3

If you're set on Python standard XML libraries, you could use something like this:

root = ET.fromstring(xmlData)
namespace = 'http://example.com'

def query(tree, nodename):
    return tree.find('{{{ex}}}{nodename}'.format(ex=namespace, nodename=nodename))

queued = query(root, 'Queued')
print queued.text

Comments

2

You can create a dictionary and directly get values out of it...

tree = ET.fromstring(xmlData)

root = {}

for child in tree:
    root[child.tag.split("}")[1]] = child.text

print root["Queued"]

5 Comments

hi, see my edit. "//child.tag for the tag Cancelled is - {example.com}Cancelled" so it is difficult to match it with "Cancelled". Is there any better way?
Hey. it works but this is just an adjustment. How do I access the text of the tags in a way where tag is a key and text is the value.
Also you might wanna change the return null to return None or return ''. Because with null, it says - NameError: global name 'null' is not defined
This maybe an alternate solution too. +1
Updated answer with a neater one.
2

With lxml.etree:

In [8]: import lxml.etree as et

In [9]: doc=et.fromstring(xmlData)

In [10]: ns={'n':'http://example.com'}

In [11]: doc.xpath('n:Queued/text()',namespaces=ns)
Out[11]: ['false']

With elementtree you can do:

import xml.etree.ElementTree as ET    
root=ET.fromstring(xmlData)    
ns={'n':'http://example.com'}
root.find('n:Queued',namespaces=ns).text
Out[13]: 'false'

1 Comment

thanks. I was wondering to find something similar in ElementTree. +1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.