使用此XML
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
<subject>Reference rates</subject>
<Sender>
<name>European Central Bank</name>
</Sender>
<Cube>
<Cube time='2013-12-20'>
<Cube currency='USD' rate='1.3655'/>
<Cube currency='JPY' rate='142.66'/>
</Cube>
</Cube>
</Envelope>
我可以像这样获得内部Cube
标签
from xml.etree.ElementTree import ElementTree
t = ElementTree()
t.parse('eurofxref-daily.xml')
day = t.find('Cube/Cube')
print 'Day:', day.attrib['time']
for currency in day:
print currency.items()
Day: 2013-12-20
[('currency', 'USD'), ('rate', '1.3655')]
[('currency', 'JPY'), ('rate', '142.66')]
问题是上面的XML是原始文件的已清理版本,它已定义了名称空间
<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube>
<Cube time='2013-12-20'>
<Cube currency='USD' rate='1.3655'/>
<Cube currency='JPY' rate='142.66'/>
</Cube>
</Cube>
</gesmes:Envelope>
当我尝试获取第一个Cube
标记时,我得到None
t = ElementTree()
t.parse('eurofxref-daily.xml')
print t.find('Cube')
None
根标记包含命名空间
root = t.getroot()
print 'root.tag:', root.tag
root.tag: {http://www.gesmes.org/xml/2002-08-01}Envelope
其子女也
for e in root.getchildren():
print 'e.tag:', e.tag
e.tag: {http://www.gesmes.org/xml/2002-08-01}subject
e.tag: {http://www.gesmes.org/xml/2002-08-01}Sender
e.tag: {http://www.ecb.int/vocabulary/2002-08-01/eurofxref}Cube
如果我在标记
中包含命名空间,我可以获得Cube
标记
day = t.find('{http://www.ecb.int/vocabulary/2002-08-01/eurofxref}Cube/{http://www.ecb.int/vocabulary/2002-08-01/eurofxref}Cube')
print 'Day: ', day.attrib['time']
Day: 2013-12-20
但这真的很难看。除了在处理之前清理文件或进行字符串操作之外,还有一种优雅的方法来处理它吗?
答案 0 :(得分:1)
除了在查询文本中包含整个名称空间URI之外,还有一种更优雅的方式。对于不支持namespaces
上的ElementTree.find
参数的python版本,lxml
提供缺少的功能,并且&#34;大部分兼容&#34;与xml.etree
:
from lxml.etree import ElementTree
t = ElementTree()
t.parse('eurofxref-daily.xml')
namespaces = { "exr": "http://www.ecb.int/vocabulary/2002-08-01/eurofxref" }
day = t.find('exr:Cube', namespaces)
print day
使用namespaces
对象,您可以一劳永逸地设置它,然后只在查询中使用前缀。
这是输出:
$ python test.py
<Element '{http://www.ecb.int/vocabulary/2002-08-01/eurofxref}Cube' at 0x7fe0f95e3290>
如果您发现前缀不优雅,那么您必须处理没有名称空间的文件。或者可能还有其他工具可以“欺骗”#34;并且在local-name()上匹配,即使命名空间生效但我也不使用它们。
在python 2.7或python 3.3或更高版本中,您可以使用与上面相同的代码,但使用xml.etree
代替lxml
,因为他们已经为这些版本添加了对名称空间的支持。< / p>