python使用lxml xpath模塊解析XML遇到的坑及解決
項(xiàng)目場(chǎng)景
解析電子病歷CDA文檔,由于CDA文檔是XML 格式的,有些節(jié)點(diǎn)的屬性值需要修改。
問(wèn)題描述
在使用python 解析xml時(shí),百度了很多方面的資料,其實(shí)都不盡人意,要么示例不夠詳細(xì),要么示例本身就是坑,總結(jié)一下,主要遇到的是這幾個(gè)方面的問(wèn)題
1.使用etree.fromstring(new_doc_content)報(bào)錯(cuò)
ValueError: Unicode strings with encoding declaration are not supported. Please use bytes input or XML fragments without declaration.
2.xpath無(wú)法獲取值、返回值為[]或者{}的問(wèn)題
原因分析
1.由于數(shù)據(jù)是從數(shù)據(jù)庫(kù)查詢出來(lái)得到的,所以etree.fromstring(new_doc_content)需要傳 byte string
2.由于CDA文檔含有字符聲明,以及命名空間的,在使用常規(guī)的xpath語(yǔ)法取不到數(shù)據(jù),或者有些text能取到,其他節(jié)點(diǎn)或者屬性值取不到。那么在含有命名空間的xml數(shù)據(jù)里,xpath需要將命名空間也帶上才能正常取到,其實(shí)問(wèn)題就出在命名空間這里,從網(wǎng)上百度出來(lái)的資料,有些命名空間寫成了
ns = {"d" : "http://www.sitemaps.org/schemas/sitemap/0.9"} url = root.xpath("http://d:loc", namespaces=ns)
正是這里把我?guī)肓苏`區(qū),使用這個(gè)方式反復(fù)調(diào)試,始終是取不到數(shù)據(jù),從其他地方查到的資料很多也是類似的這種寫法,同時(shí)也忽略掉了一些不一樣的點(diǎn)。
例如這樣的寫法:
url = root.xpath("http://d:loc", namespaces={'d' : 'http://www.sitemaps.org/schemas/sitemap/0.9'})`
咋一看只是namespaces的值事先定義好了而已,沒有往其他方向想。
后來(lái)通過(guò)foo_tree = etree.ElementTree(xml) 然后通過(guò)遍歷foo_tree.getroot()修改屬性內(nèi)容,雖然說(shuō)能解決,但是還是想通過(guò)xpath來(lái)查詢定位,因?yàn)橹芭老x用過(guò)xpath,知道它的便利之處,回過(guò)頭來(lái)還是要去解決xpath這個(gè)問(wèn)題。
猛回頭,發(fā)現(xiàn)namespaces字典定義的區(qū)別,單引號(hào) 和雙引號(hào)這里有所不同。那就是試試把,將雙引號(hào)改成了單引號(hào)。
啪,完美,它起作用了,能找到節(jié)點(diǎn)了。
解決方案
1.將str轉(zhuǎn)換成byte string
etree.fromstring(new_doc_content.encode('utf-8'))
2.將namespaces定義的字典中的雙引號(hào)換成單引號(hào)
url = root.xpath("http://d:loc", namespaces={'d' : 'http://www.sitemaps.org/schemas/sitemap/0.9'})`
示例XML
<?xml version="1.0" encoding="UTF-8"?> <ClinicalDocument xmlns="urn:hl7-org:v3" xmlns:mif="urn:hl7-org:v3/mif" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:hl7-org:v3 ..\sdschemas\SDA.xsd"> <realmCode code="CN"/> <typeId root="2.16.840.1.113883.1.3" extension="POCD_MT000040"/> <templateId root="2.16.156.10011.2.1.1.33"/> <id root="2.16.156.10011.1.1" extension="545ED988-5235-45F1-BBFD-9326D74FAA43"/> <code code="00000" codeSystem="545ED988-5235-45F1-BBFD-9326D74FAA43" codeSystemName="衛(wèi)生信息共享文檔規(guī)范編碼體系"/> <title>測(cè)試</title> <effectiveTime value="20220407090145"/> <confidentialityCode code="N" codeSystem="2.16.840.1.113883.5.25" codeSystemName="Confidentiality" displayName="正常訪問(wèn)保密級(jí)別"/> <languageCode code="zh-CN"/> <setId/> <versionNumber/> <recordTarget typeCode="RCT" contextControlCode="OP"> <patientRole classCode="PAT"> <id root="2.16.156.10011.1.11" extension="00000000"/> <id root="2.16.156.10011.1.12" extension="00000000"/> <id root="2.16.156.10011.1.24" extension="-"/> <patient classCode="PSN" determinerCode="INSTANCE"> <name>XXX</name> <administrativeGenderCode code="1" displayName="男性" codeSystem="2.16.156.10011.2.3.3.4" codeSystemName="生理性別代碼表(GB/T 2261.1)"/> <age value="0" unit="歲"/> </patient> </patientRole> </recordTarget> </ClinicalDocument>
示例Python
xml = etree.fromstring(new_doc_content.encode('utf-8')) # 示例的默認(rèn)命名空間是urn:hl7-org:v3,使用xpath需要將命名空間帶上 effective_time = xml.xpath("http://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)
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
python使用wxpython開發(fā)簡(jiǎn)單記事本的方法
這篇文章主要介紹了python使用wxpython開發(fā)簡(jiǎn)單記事本的方法,涉及Python使用wxPython實(shí)現(xiàn)桌面圖形應(yīng)用程序的技巧,需要的朋友可以參考下2015-05-05python圖像處理基本操作總結(jié)(PIL庫(kù)、Matplotlib及Numpy)
這篇文章主要給大家介紹了關(guān)于python圖像處理基本操作的相關(guān)資料,主要利用的是PIL庫(kù)、Matplotlib及Numpy等處理方法,需要的朋友可以參考下2021-06-06Python zip()函數(shù)用法實(shí)例分析
這篇文章主要介紹了Python zip()函數(shù)用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Python zip()函數(shù)的功能、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2018-03-03celery在python爬蟲中定時(shí)操作實(shí)例講解
在本篇文章里小編給大家整理了一篇關(guān)于celery在python爬蟲中定時(shí)操作實(shí)例講解內(nèi)容,需要的朋友們可以參考下。2020-11-11Python之NumPy(axis=0 與axis=1)區(qū)分詳解
這篇文章主要介紹了Python之NumPy(axis=0 與axis=1)區(qū)分詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05python之線程池map()方法傳遞多參數(shù)list
這篇文章主要介紹了python之線程池map()方法傳遞多參數(shù)list問(wèn)題,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03