python使用lxml xpath模块解析XML遇到的坑

python使用lxml xpath模块解析XML遇到的坑,第1张

项目场景:

解析电子病历CDA文档,由于CDA文档是XML 格式的,有些节点的属性值需要修改。



问题描述

在使用python 解析xml时,百度了很多方面的资料,其实都不尽人意,要么示例不够详细,要么示例本身就是坑,总结一下,主要遇到的是这几个方面的问题

1. 使用etree.fromstring(new_doc_content)报错

ValueError: Unicode strings with encoding declaration are not supported. Please use bytes input or XML fragments without declaration.

2.xpath无法获取值、返回值为[]或者{}的问题 原因分析:

1.由于数据是从数据库查询出来得到的,所以etree.fromstring(new_doc_content)需要传 byte string
2.由于CDA文档含有字符声明,以及命名空间的,在使用常规的xpath语法取不到数据,或者有些text能取到,其他节点或者属性值取不到。


那么在含有命名空间的xml数据里,xpath需要将命名空间也带上才能正常取到,其实问题就出在命名空间这里,从网上百度出来的资料,有些命名空间写成了

ns = {"d" : "http://www.sitemaps.org/schemas/sitemap/0.9"}
url = root.xpath("//d:loc", namespaces=ns)

正是这里把我带入了误区,使用这个方式反复调试,始终是取不到数据,从其他地方查到的资料很多也是类似的这种写法,同时也忽略掉了一些不一样的点。


例如这样的写法:

url = root.xpath("//d:loc", namespaces={'d' : 'http://www.sitemaps.org/schemas/sitemap/0.9'})`

咋一看只是namespaces的值事先定义好了而已,没有往其他方向想。


后来通过foo_tree = etree.ElementTree(xml) 然后通过遍历foo_tree.getroot()修改属性内容,虽然说能解决,但是还是想通过xpath来查询定位,因为之前爬虫用过xpath,知道它的便利之处,回过头来还是要去解决xpath这个问题。


猛回头,发现namespaces字典定义的区别,单引号 和双引号这里有所不同。


那就是试试把,将双引号改成了单引号。


啪,完美,它起作用了,能找到节点了。


解决方案:

1.将str转换成byte string

etree.fromstring(new_doc_content.encode('utf-8'))

2.将namespaces定义的字典中的双引号换成单引号

url = root.xpath("//d:loc", namespaces={'d' : 'http://www.sitemaps.org/schemas/sitemap/0.9'})`
示例XML:

测试 XXX

示例Python:
xml = etree.fromstring(new_doc_content.encode('utf-8'))
# 示例的默认命名空间是urn:hl7-org:v3,使用xpath需要将命名空间带上
effective_time = xml.xpath("//x:effectiveTime[@*]", namespaces={'x': 'urn:hl7-org:v3'})
extension = xml.xpath('//x:recordTarget//x:patientRole/x:id[@extension]',
                                         namespaces={'x': 'urn:hl7-org:v3'})
print(effective_time)
print(extension)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/569819.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)