如何解决在 Python XPath 查询中注册命名空间
这是我拥有的 XML 文档:
<products xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Product Id="1">
<Product Id="1_1">
<Attribute Name="Whatever"></Attribute>
</Product>
<Attributes xmlns="http://some/path/to/entity/def">
<Attribute Name="Identifier">NumberOne</Attribute>
</Attributes>
</Product>
<Product Id="2">
<Attributes xmlns="http://some/path/to/entity/def">
<Attribute Name="Identifier">NumberTwo</Attribute>
</Attributes>
</Product>
</products>
我正在尝试使用 XPath 通过其子 Attributes.Attribute[Name=Identifier]
值(例如 "NumberOne"
)获取产品。
所以在这种情况下,我的预期结果是:
<Product Id="1">
<Product Id="1_1">
<Attribute Name="Whatever"></Attribute>
</Product>
<Attributes xmlns="http://some/path/to/entity/def">
<Attribute Name="Identifier">NumberOne</Attribute>
</Attributes>
</Product>
基于 this 的解释,我尝试使用 lxml 库在 Python 中实现查询:
found_products = xml_tree_from_string.xpath('//products//Product[c:Attributes[Attribute[@Name="Identifier" and text()="NumberOne"]]]',namespaces={"c": "http://some/path/to/entity/def"})
不幸的是,由于 Attributes 命名空间定义,这永远不会返回结果。
我错过了什么?
解决方法
我错过了什么?
您没有注意到 Attribute
也与 Attributes
位于同一命名空间中,因为默认命名空间声明是由后代 XML 元素继承的。
因此,只需在您的 XPath 中将 c:
添加到 Attribute
,它应该可以作为 Jack 的答案的 you observed in your comment。
您需要首先定义一个命名空间映射,为那些没有的命名空间声明一个前缀(就像这里的情况),然后应用 xpath:
from lxml import etree
prods ="""[your xml above]"""
ns = { (k if k else "xx"):(v) for k,v in doc.xpath('//namespace::*') } #create ns map
doc = etree.XML(prods)
for product in doc.xpath('//products//Product[.//xx:Attribute[@Name="Identifier"][text()="NumberOne"]]',namespaces=ns):
print(etree.tostring(product).decode())
输出:
<Product xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Id="1">
<Product Id="1_1">
<Attribute Name="Whatever"/>
</Product>
<Attributes xmlns="http://some/path/to/entity/def">
<Attribute Name="Identifier">NumberOne</Attribute>
</Attributes>
</Product>
要取消命名空间属性,请将 for
循环更改为:
for product in doc.xpath('//products//Product[.//xx:Attribute[@Name="Identifier"][text()="NumberOne"]]',namespaces=ns):
etree.cleanup_namespaces(doc) #note: the parameter is "doc",not "product"
print(etree.tostring(product).decode())
输出:
<Product Id="1">
<Product Id="1_1">
<Attribute Name="Whatever"/>
</Product>
<Attributes xmlns="http://some/path/to/entity/def">
<Attribute Name="Identifier">NumberOne</Attribute>
</Attributes>
</Product>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。