我无法找到信息,如何使用命名空间解析我的XML:
我有这个xml:
<par:Request xmlns:par="http://somewhere.net/actual">
<par:actual>blabla</par:actual>
<par:documentType>string</par:documentType>
</par:Request>
并试图解析它:
dom = ET.parse(u'C:\\filepath\\1.xml')
rootxml = dom.getroot()
for subtag in rootxml.xpath(u'//par:actual'):
#do something
print(subtag)
并且有例外,因为它不知道名称空间前缀。 有没有最好的方法来解决这个问题,计算该脚本将不知道它要解析的文件和标签将要搜索?
搜索网络和stackoverflow我发现,如果我要添加:
namespace = {u'par': u"http://somewhere.net/actual"}
for subtag in rootxml.xpath(u'//par:actual', namespaces=namespace):
#do something
print(subtag)
有效。完善。但我不知道我将解析哪个XML,并且我的脚本也不知道搜索标记(例如//par:actual
)。所以,我需要找到以某种方式从XML中提取命名空间的方法。
我找到了很多方法,如何提取名称空间URI,例如:
print(rootxml.tag)
print(rootxml.xpath('namespace-uri(.)'))
print(rootxml.xpath('namespace-uri(/*)'))
但是我应该如何提取前缀来创建ElementTree想要的字典呢?我不想在xml体上使用正则表达式怪物来提取前缀,我相信必须存在支持的方式,不是吗?
也许有一些方法让我可以通过ETree命名空间从XML中提取为字典(就像ETree想要的那样!)而不用手动操作?
答案 0 :(得分:2)
您不能依赖根元素上的名称空间声明:不能保证声明甚至会存在,或者文档将始终具有相同名称空间的相同前缀。
假设您要通过某种方式传递要搜索的标记(因为您说它不为您的脚本所知),您还应该提供一种传递命名空间映射的方法。或者使用James Clark表示法,例如{http://somewhere.net/actual}actual
(ETXPath
支持此语法,而“普通”xpath则不支持,但如果你不使用.findall()
,你也可以使用其他方法不需要完整的xpath)
如果你根本不关心前缀,你也可以在xpath中使用local-name()
函数,例如。 //*[local-name()="actual"]
(但你不会“真的”确定它是正确的“实际”)
答案 1 :(得分:1)
哦,我找到了。
我们这样做之后:
dom = ET.parse(u'C:\\filepath\\1.xml')
rootxml = dom.getroot()
对象rootxml包含字典nsmap,其中包含我想要的所有命名空间。
所以,我发现最简单的解决方案:
dom = ET.parse(u'C:\\filepath\\1.xml')
rootxml = dom.getroot()
nss = rootxml.nsmap
for subtag in rootxml.xpath(u'//par:actual', namespaces=nss):
#do something
print(subtag)
有效。
UPD:如果用户理解他使用的XML中的'par'是什么意思,那就有效。例如,在任何其他操作之前将假定的命名空间与现有命名空间进行比较。
尽管如此,我喜欢XPath的多种变体,它理解{...}实际,这就是我试图实现的目标。
答案 2 :(得分:1)
使用 Python 3.8.2 我发现这个问题有同样的问题。
这是我找到的解决方案,将命名空间放在 XPath 查询中。 (在 {} 之间)
ApplicationArea = BOD_IN_tree.find('.//ApplicationArea', ns)
if(ApplicationArea is None):
ApplicationArea = BOD_IN_tree.find('.//{http://www.defaultNamespace.com/2}ApplicationArea', ns)
我搜索没有命名空间的元素,如果没有找到,则再次搜索。我无法控制入站文档,有些有命名空间,有些没有。
我希望这会有所帮助!