我该如何在Python中解析这个XML字符串?

8
我的XML字符串是 -
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>"""

我正在尝试解析并获取标签的值 - Cancelled,MessageId,SMSError等。我正在使用Python的Elementtree库。到目前为止,我已经尝试过像这样的操作 -
root = ET.fromstring(xmlData)
print root.find('Sent')  // gives None
for child in root:
    print chil.find('MessageId') // also gives None

虽然我能够使用 - 打印标签

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

和它们各自的值与 -
for child in root:
    print child.text

如何获得类似于 -

print child.Queued // will print false

就像在PHP中,我们可以通过根目录访问它们 -

$xml = simplexml_load_string($data);
$status = $xml->SMSError;
4个回答

8

您的文档具有命名空间,搜索时需要包含命名空间:

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

输出:

<Element '{http://example.com}Sent' at 0x1043e0690>
<Element '{http://example.com}MessageID' at 0x1043e0350>
< p > find()findall() 方法也可以使用命名空间映射;您可以搜索任意前缀,并且该前缀将在该映射中查找,以节省输入:

nsmap = {'n': 'http://example.com'}
print root.find('n:Sent', namespaces=nsmap)
print root.find('n:MessageID', namespaces=nsmap)

看看 @eclaird 的回答。我认为你也在尝试做同样的事情。+1 - Hussain
它仍然使用nsmap打印“None”。我认为nsmap有问题。 - Hussain
我之前使用的是xml.etree.ElementTree,链接在这里:[http://docs.python.org/2/library/xml.etree.elementtree.html#module-xml.etree.ElementTree]。我认为你正在使用`lxml.etree`,就像@root正在使用的一样。 - Hussain
@HussainTamboli:不,我正在使用xml.etree,Python 2.7。 lxml支持相同的API(虽然有一些改进,但在两者中都是相同的)。 - Martijn Pieters
嗨,root.find('n:Sent', namespaces=nsmap) 打印的是对象。在后面添加 .text 即可。 - Hussain
显示剩余4条评论

3
如果您坚持使用Python标准的XML库,您可以使用类似以下的方法:
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

2

您可以创建一个字典,并直接从中获取值...

tree = ET.fromstring(xmlData)

root = {}

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

print root["Queued"]

嗨,看看我的编辑。 "//child.tag for the tag Cancelled is - {http://example.com}Cancelled" 所以很难与 "Cancelled" 匹配。有更好的方法吗? - Hussain
嘿,它能工作,但这只是一个调整。我如何以标签为键,文本为值的方式访问标签的文本? - Hussain
你可能想将 return null 更改为 return Nonereturn ''。因为使用 null 会出现 - NameError: global name 'null' is not defined - Hussain
这也许是一个替代方案。 +1 - Hussain
更新答案,现在更整洁了。 - ATOzTOA

2

使用 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']

使用elementtree,您可以做到以下事情:
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'

谢谢。我在想是否能在ElementTree中找到类似的东西。+1 - Hussain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接