程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python lxml 清洗 XML 清除 node 和 attribute

編輯:Python

引言:

項目中會遇到數據遷移,怎麼保准新的數據和老的數據內容保持一致呢,有時需要進行內容測試,這就涉及到 XML 內容的比較,由於數據處理方式改變,需要忽略期望中的不同,所以對特殊的 xpath 進行處理。綜合各種研究,覺得 lxml 效率最高,對 xml 的處理非常方便,本文將通過一個例子來解決工作中遇到的數據清洗問題。
內容提要:

  1. XML namespace 概要
  2. lxml 對 XML的操作
  3. lxml 應用清洗XML

XML namespace

有關 XML namespace,可以參考 XML 命名空間,namesp主要是用來解決命名沖突,一般復雜的 XML tag 都帶前綴,前綴就代表命名空間。

例如:這是一個正常的 XML

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:B" xmlns:B="urn:B" elementFormDefault="qualified">
<element name="foo">
<complexType>
<element name="bar" type="B:myType"/>
</complexType>
</element>
<complexType name="myType">
<choice>
<element name="baz" type="string"/>
<element name="bas" type="string"/>
</choice>
</complexType>
</schema>

我們也可以用前綴的方式表示:
xmlns:myprefix="http://www.w3.org/2001/XMLSchema"

<myprefix:schema xmlns:myprefix="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:B" xmlns:B="urn:B" elementFormDefault="qualified">
<myprefix:element name="foo">
<myprefix:complexType>
<myprefix:element name="bar" type="B:myType"/>
</myprefix:complexType>
</myprefix:element>
<myprefix:complexType name="myType">
<myprefix:choice>
<myprefix:element name="baz" type="string"/>
<myprefix:element name="bas" type="string"/>
</myprefix:choice>
</myprefix:complexType>
</myprefix:schema>

lxml 對 XML的操作

  1. 解析 XML:
import lxml.etree as XE
root = XE.fromstring(xml_content)
  1. 獲取 namesp
namespaces=root.nsmap
  1. 定位 node
    注意:需要用相對 xpath,不支持絕對 xpath,對於還前綴的tag 一定要帶上 namespace
nodes = root.findall(rele_xpath_ignore, namespaces=root.nsmap)
  1. node 移除
node.getparent().remove(node)
  1. attribute 清除
node.attrib.pop(attri_name_list[0])

lxml 應用清洗XML

需求:
就拿上面的 xml 為例

  1. 移除節點 myprefix:schema/myprefix:complexType/myprefix:choice
  2. 移除 attribute
    myprefix:schema/myprefix:element/[@name]

方案:

  1. 可以將需要處理的 Xpath 加到一個列表中,或從某個文件讀取
  2. 滿足 xpath 的 node 可能很多,所以需要用個循環處理
  3. 要同時處理 node 和 attribute
  4. 如果需要處理很多 XML,每個 XML 處理的 xpath 可能不同,所以盡量跳過 本 XML中不匹配的 XPATH
  5. 想得到趕緊的純 xml 內容,把 namespac也清除

完整代碼:

import re
import lxml.etree as XE
def ignore_xpath_handled_by_lxml(xml_content):
ignore_xpath_set = set()
ignore_xpath_set.add("myprefix:schema/myprefix:complexType/myprefix:choice")
ignore_xpath_set.add("myprefix:schema/myprefix:element/[@name]")
root = XE.fromstring(xml_content)
root_tag_name = re.findall(".*\}(.*)", root.tag)[0]
for xpath_ignore in ignore_xpath_set:
xpath_ignore_tag = xpath_ignore.split("/")[0].split(":")[1]
# reletive path
index = xpath_ignore.find("/")
rele_xpath_ignore = ".//" + xpath_ignore[index+1:]
# handle the xpath: mached the tag
if xpath_ignore_tag == root_tag_name:
try:
attri_name_list = re.findall(".*\[@(.*)\].*", xpath_ignore)
nodes = root.findall(rele_xpath_ignore, namespaces=root.nsmap)
if len(nodes) > 0:
for node in nodes:
if len(attri_name_list) > 0:
node.attrib.pop(attri_name_list[0])
else:
node.getparent().remove(node)
except Exception as e:
print("Error: {}".format(e))
else:
continue
root_tag = "myprefix" + ":" + root_tag_name
ignore_result = str(XE.tostring(root, pretty_print=True, encoding="unicode"))
namespace_pattern = re.compile('<' + root_tag + r' xmlns(.|\\s)*>')
content_without_namespace = re.sub(namespace_pattern, '<'+ root_tag + '>', ignore_result)
return content_without_namespace
if __name__ == "__main__":
xml_string = ''' <myprefix:schema xmlns:myprefix="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:B" xmlns:B="urn:B" elementFormDefault="qualified"> <myprefix:element name="foo"> <myprefix:complexType> <myprefix:element name="bar" type="B:myType"/> </myprefix:complexType> </myprefix:element> <myprefix:complexType name="myType"> <myprefix:choice> <myprefix:element name="baz" type="string"/> <myprefix:element name="bas" type="string"/> </myprefix:choice> </myprefix:complexType> </myprefix:schema> '''
new_xml_string = ignore_xpath_handled_by_lxml(xml_string)
print(new_xml_string)

輸出:

<myprefix:schema>
<myprefix:element>
<myprefix:complexType>
<myprefix:element type="B:myType"/>
</myprefix:complexType>
</myprefix:element>
<myprefix:complexType name="myType">
</myprefix:complexType>
</myprefix:schema>

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved