Python3使用lxml.etree.find无法获取XML元素值的问题
解决带默认命名空间的XML节点查找问题
我之前也碰到过一模一样的问题!带默认命名空间的XML用lxml查找节点真的很容易踩坑,我来给你捋清楚怎么解决:
首先得明白为什么你用root_node.find('.//returnType')返回None:你的XML里有个默认命名空间xmlns="http://something.com/Schema/V2/Result",所有子节点本质上都属于这个命名空间,只是XML里没写前缀而已。lxml会把这些节点识别成<Element {http://something.com/Schema/V2/Result}returnType ...>这种带命名空间的形式,直接用节点名查找自然找不到。
你之前尝试用root.nsmap报错,是因为root.nsmap里默认命名空间对应的键是空字符串'',而lxml的ElementPath不支持空前缀,所以才会抛出ValueError: empty namespace prefix is not supported in ElementPath。
正确的解决方案:自定义命名空间映射
给默认命名空间起一个非空的前缀(比如ns),然后在查找时指定这个命名空间映射,就能正常找到节点了。直接上代码:
from lxml import etree as et # 你的字节类型XML响应 response_content = b"""<?xml version="1.0" encoding="utf-8"?> <result xmlns="http://something.com/Schema/V2/Result"> <success>false</success> <returnType>ERROR</returnType> <errors> <error> <message>Invalid signature</message> <code>3002</code> </error> </errors> </result>""" root_node = et.fromstring(response_content) # 定义命名空间映射,给默认命名空间起个前缀 ns_map = {'ns': 'http://something.com/Schema/V2/Result'} # 查找returnType节点并获取值 return_type_elem = root_node.find('.//ns:returnType', namespaces=ns_map) if return_type_elem: return_type = return_type_elem.text print(f"returnType: {return_type}") # 输出 ERROR # 同理获取其他节点值 success_val = root_node.find('.//ns:success', namespaces=ns_map).text error_msg = root_node.find('.//ns:message', namespaces=ns_map).text error_code = root_node.find('.//ns:code', namespaces=ns_map).text print(f"success: {success_val}") # 输出 false print(f"错误信息: {error_msg}, 错误码: {error_code}") # 输出 错误信息: Invalid signature, 错误码: 3002
应急方案:忽略命名空间查找(不推荐)
如果临时不想处理命名空间,可以用local-name()匹配节点的本地名称,绕过命名空间检查,但这种方法如果XML里有同名不同命名空间的节点会出错,所以只建议应急用:
return_type_elem = root_node.find('.//*[local-name()="returnType"]') if return_type_elem: print(return_type_elem.text) # 输出 ERROR
总的来说,优先用第一种自定义命名空间映射的方法,既规范又不容易出问题。
内容的提问来源于stack exchange,提问作者Sam_slo
相关产品推荐
相关产品推荐

