Python使用XPath获取XML任意层级带href属性元素的方法
问题原因
你编写的XPath语法本身对于无命名空间的XML是完全正确的,你给出的示例XML运行你提供的代码可以得到预期结果。实际处理大文件返回空列表的核心原因大概率是目标XML带有命名空间声明,href属性归属到了特定命名空间下,无命名空间前缀的@href无法匹配到对应属性,这是lxml处理带命名空间XML时的常见问题。
解决方法
方法1:确认命名空间后精准匹配
首先先打印XML根节点的命名空间映射,确认href属性所属的命名空间:
from lxml import etree with open(file, 'rb') as f: xml_tree = etree.parse(f) # 输出所有命名空间,确认href归属 print(xml_tree.getroot().nsmap)
如果输出结果包含类似{'xlink': 'http://www.w3.org/1999/xlink'}的项,说明href属于xlink命名空间,修改XPath传入命名空间参数即可:
with open(file, 'rb') as f: xml_tree = etree.parse(f) ns = xml_tree.getroot().nsmap # 匹配xlink命名空间下的href属性 href_elements = xml_tree.xpath("//*[@xlink:href]", namespaces=ns)
方法2:通用命名空间无感知匹配
如果不想额外处理命名空间,也可以直接匹配属性的本地名,适配所有命名空间场景:
from lxml import etree with open(file, 'rb') as f: xml_tree = etree.parse(f) # 忽略命名空间,匹配所有属性名等于href的元素 href_elements = xml_tree.xpath("//*[@*[local-name() = 'href']]")
额外兼容方案
如果XML存在轻微格式错误导致解析失败,可以开启解析器的容错模式:
from lxml import etree # 开启容错模式,容忍轻微格式异常 parser = etree.XMLParser(recover=True) with open(file, 'rb') as f: xml_tree = etree.parse(f, parser=parser) href_elements = xml_tree.xpath("//*[@*[local-name() = 'href']]")
内容的提问来源于stack exchange,提问作者Cameron Gould
相关产品推荐
相关产品推荐

