Python?基于xml.etree.ElementTree實(shí)現(xiàn)XML對(duì)比示例詳解
測(cè)試環(huán)境
Python 3.6
Win10
代碼實(shí)現(xiàn)
#!/usr/bin/env python 3.4.0
#-*- encoding:utf-8 -*-
__author__ = 'shouke'
import xml.etree.ElementTree as ET
def compare_xml_node_attributes(xml_node1, xml_node2):
result = []
node1_attributes_dict = xml_node1.attrib
node2_attributes_dict = xml_node2.attrib
for attrib1, value in node1_attributes_dict.items():
value2 = node2_attributes_dict.get(attrib1)
if value == value2:
node2_attributes_dict.pop(attrib1)
else:
if value2:
attrib2 = attrib1
node2_attributes_dict.pop(attrib2)
else:
attrib2 = '不存在'
result.append('結(jié)點(diǎn)1屬性:{attrib1} 值:{value1},結(jié)點(diǎn)2屬性:{attrib1} 值:{value2}'.format(attrib1=attrib1 or '不存在',
value1=value or '不存在',
attrib2=attrib2,
value2=value2 or '不存在'))
for attrib2, value2 in node2_attributes_dict.items():
result.append('結(jié)點(diǎn)1屬性:{attrib1} 值:{value1},結(jié)點(diǎn)2屬性:{attrib1} 值:{value2}'.format(attrib1='不存在',
value1='不存在',
attrib2=attrib2,
value2=value2))
return result
def compare_xml_node_children(xml_node1, xml_node2, node1_xpath, node2_xpath):
def get_node_children(xml_node, node_xpath):
result = {}
for child in list(xml_node):
if child.tag not in result:
result[child.tag] = [{'node':child, 'xpath': '%s/%s[%s]' % (node_xpath, child.tag, 1)}]
else:
result[child.tag].append({'node':child, 'xpath': '%s/%s[%s]' % (node_xpath, child.tag, len(result[child.tag])+1)})
return result
result = []
children_of_node1_dict = get_node_children(xml_node1, node1_xpath)
children_of_node2_dict = get_node_children(xml_node2, node2_xpath)
temp_list1 = []
temp_list2 = []
for child_tag, child_node_list in children_of_node1_dict.items():
second_child_node_list = children_of_node2_dict.get(child_tag, [])
if not second_child_node_list:
# 獲取xml1中比xml2中多出的子結(jié)點(diǎn)
for i in range(0, len(child_node_list)):
temp_list1.append('%s/%s[%s]' % (node1_xpath, child_node_list[i]['node'].tag, i+1))
continue
for first_child, second_child in zip(child_node_list, second_child_node_list):
result.extend(compare_xml_nodes(first_child['node'], second_child['node'], first_child['xpath'], second_child['xpath']))
# 獲取xml2中對(duì)應(yīng)結(jié)點(diǎn)比xml1中對(duì)應(yīng)結(jié)點(diǎn)多出的同名子結(jié)點(diǎn)
for i in range(len(child_node_list), len(second_child_node_list)):
temp_list2.append('%s/%s[%s]' % (node2_xpath, second_child_node_list[i]['node'].tag, i+1))
children_of_node2_dict.pop(child_tag)
if temp_list1:
result.append('子結(jié)點(diǎn)不一樣:xml1結(jié)點(diǎn)(xpath:{xpath1})比xml2結(jié)點(diǎn)(xpath:{xpath2})多了以下子結(jié)點(diǎn):\n{differences}'.format (xpath1=node1_xpath,
xpath2=node2_xpath,
differences='\n'.join(temp_list1)))
# 獲取xml2比xml1中多出的子結(jié)點(diǎn)
for child_tag, child_node_list in children_of_node2_dict.items():
for i in range(0, len(child_node_list)):
temp_list2.append('%s/%s[%s]' % (node1_xpath, child_node_list[i]['node'].tag, i+1))
if temp_list2:
result.append('子結(jié)點(diǎn)不一樣:xml1結(jié)點(diǎn)(xpath:{xpath1})比xml2結(jié)點(diǎn)(xpath:{xpath2})少了以下子結(jié)點(diǎn):\n{differences}'.format (xpath1=node1_xpath,
xpath2=node2_xpath,
differences='\n'.join(temp_list2)))
return result
def compare_xml_nodes(xml_node1, xml_node2, node1_xpath='', node2_xpath=''):
result = []
# 比較標(biāo)簽
if xml_node1.tag != xml_node2.tag:
result.append('標(biāo)簽不一樣:xml1結(jié)點(diǎn)(xpath:{xpath1}):{tag1},xml2結(jié)點(diǎn)(xpath:{xpath2}):{tag2}'.format (xpath1=node1_xpath,
tag1=xml_node1.tag,
xpath2=node2_xpath,
tag2=xml_node2.tag))
# 比較文本
if xml_node1.text != xml_node2.text:
result.append('文本不一樣:xml1結(jié)點(diǎn)(xpath:{xpath1}):{text1},xml2結(jié)點(diǎn)(xpath:{xpath2}):{text2}'.format (xpath1=node1_xpath,
tag1=xml_node1.text or '',
xpath2=node2_xpath,
tag2=xml_node2.text or ''))
# 比較屬性
res = compare_xml_node_attributes(xml_node1, xml_node2)
if res:
result.append('屬性不一樣:xml1結(jié)點(diǎn)(xpath:{xpath1}),xml2結(jié)點(diǎn)(xpath:{xpath2}):\n{differences}'.format (xpath1=node1_xpath,
xpath2=node2_xpath,
differences='\n'.join(res)))
# 比較子結(jié)點(diǎn)
res = compare_xml_node_children(xml_node1, xml_node2, node1_xpath, node2_xpath)
if res:
result.extend(res)
return result
def compare_xml_strs(xml1_str, xml2_str, mode=3):
'''
@param: mode 比較模式,預(yù)留,暫時(shí)沒(méi)用。目前默認(rèn) xml 子元素如果為列表,則列表有序列表,按序比較
'''
root1 = ET.fromstring(xml1_str.strip())
root2 = ET.fromstring(xml2_str.strip())
return compare_xml_nodes(root1, root2, '/%s' % root1.tag, '/%s' % root2.tag)
測(cè)試運(yùn)行
xml_str1 = '''
<?xml version = "1.0" encoding="utf-8" ?>
<data>
<country name="Liechtenstein">
<rangk>1</rangk>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E" ></neighbor>
<neighbor name="Switzerland" direction="W" ></neighbor>
</country>
<country name="Singpore">
<rank>4</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N" ></neighbor>
</country>
<country name="Panama">
<rank>68</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W" ></neighbor>
<neighbor name="Colombia" direction="W" ></neighbor>
</country>
</data>
'''
xml_str2 = '''
<?xml version = "1.0" encoding="utf-8" ?>
<data>
<country name="Liechtenstein">
<rangk>1</rangk>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E" ></neighbor>
<neighbor name="Switzerland" direction="W" ></neighbor>
</country>
<country name="Singpore">
<rank>4</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N" ></neighbor>
</country>
<country name="Panama">
<rank>68</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W" ></neighbor>
<neighbor name="Colombia" direction="W" ></neighbor>
</country>
</data>
'''
xml_str3 = '''
<?xml version = "1.0" encoding="utf-8" ?>
<data>
<class name="computer">
<rangk>1</rangk>
<year>unknow</year>
<addr>sz</addr>
<book name="java programming" price="10" ></book>
<book name="python programming" price="10" ></book>
</class>
<class name="philosophy">
<rangk>2</rangk>
<year>unknown</year>
<book name="A little history of philosophy" price="15" ></book>
<book name="contemporary introduction" price="15" ></book>
</class>
<class name="history">
<rangk>3</rangk>
<year>unknown</year>
<addr>other addr</addr>
<book name="The South China Sea" price="10" ></book>
<book name="Chinese Among Others" price="10" ></book>
</class>
</data>
'''
xml_str4 = '''
<?xml version = "1.0" encoding="utf-8" ?>
<data>
<class name="computer">
<year>unknow</year>
<addr>sz</addr>
<book name="java programming" price="10" ></book>
<book name="python programming" price="10" ></book>
</class>
<class name="philosophy">
<year>unknown</year>
<addr>other addr</addr>
<book name="A little history of philosophy" price="15" ></book>
<book name="contemporary introduction" price="16" ></book>
</class>
</data>
'''
if __name__ == '__main__':
res_list = compare_xml_strs(xml_str1, xml_str2)
if res_list:
print('xml1和xml2不一樣:\n%s' % '\n'.join(res_list))
else:
print('xml1和xml2一樣')
res_list = compare_xml_strs(xml_str3, xml_str4)
if res_list:
print('xml3和xml4不一樣:\n%s' % '\n'.join(res_list))
else:
print('xml3和xml4一樣')
運(yùn)行結(jié)果
xml1和xml2一樣 xml3和xml4不一樣: 子結(jié)點(diǎn)不一樣:xml1結(jié)點(diǎn)(xpath:/data/class[1])比xml2結(jié)點(diǎn)(xpath:/data/class[1])多了以下子結(jié)點(diǎn): /data/class[1]/rangk[1] 屬性不一樣:xml1結(jié)點(diǎn)(xpath:/data/class[2]/book[2]),xml2結(jié)點(diǎn)(xpath:/data/class[2]/book[2]): 結(jié)點(diǎn)1屬性:price 值:15,結(jié)點(diǎn)2屬性:price 值:16 子結(jié)點(diǎn)不一樣:xml1結(jié)點(diǎn)(xpath:/data/class[2])比xml2結(jié)點(diǎn)(xpath:/data/class[2])多了以下子結(jié)點(diǎn): /data/class[2]/rangk[1] 子結(jié)點(diǎn)不一樣:xml1結(jié)點(diǎn)(xpath:/data/class[2])比xml2結(jié)點(diǎn)(xpath:/data/class[2])少了以下子結(jié)點(diǎn): /data/class[2]/addr[1]
到此這篇關(guān)于Python 基于xml.etree.ElementTree實(shí)現(xiàn)XML對(duì)比的文章就介紹到這了,更多相關(guān)Python 實(shí)現(xiàn)XML對(duì)比內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Tensorflow訓(xùn)練MNIST手寫數(shù)字識(shí)別模型
這篇文章主要為大家詳細(xì)介紹了Tensorflow訓(xùn)練MNIST手寫數(shù)字識(shí)別模型,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02
opencv-python圖像配準(zhǔn)(匹配和疊加)的實(shí)現(xiàn)
圖像配準(zhǔn)需是指對(duì)不同條件下得到的兩幅或多幅圖像進(jìn)行匹配、疊加的過(guò)程。本文詳細(xì)的介紹了如何使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
Python使用Appium在移動(dòng)端抓取微博數(shù)據(jù)的實(shí)現(xiàn)
Appium是移動(dòng)端的自動(dòng)化測(cè)試工具,讀者可以類比為PC端的selenium。通過(guò)它,我們可以驅(qū)動(dòng)App完成自動(dòng)化的一系列操作,同樣也可以爬取需要的內(nèi)容,本文就來(lái)介紹一下如何在移動(dòng)端抓取微博數(shù)據(jù),感興趣的可以了解一下2021-08-08
Python Lambda函數(shù)使用總結(jié)詳解
這篇文章主要介紹了Python Lambda函數(shù)使用總結(jié)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
python中heapq堆排算法的實(shí)現(xiàn)
這篇文章主要介紹了python中heapq堆排算法的實(shí)現(xiàn),該模塊提供了堆排序算法的實(shí)現(xiàn)。堆是二叉樹,最大堆中父節(jié)點(diǎn)大于或等于兩個(gè)子節(jié)點(diǎn),最小堆父節(jié)點(diǎn)小于或等于兩個(gè)子節(jié)點(diǎn)。下面文章更多詳細(xì)介紹,需要的小伙伴可以參考一下2022-05-05
對(duì)Python的Django框架中的項(xiàng)目進(jìn)行單元測(cè)試的方法
這篇文章主要介紹了對(duì)Python的Django框架中的項(xiàng)目進(jìn)行單元測(cè)試的方法,使用Django中的tests.py模塊可以輕松地檢測(cè)出一些常見錯(cuò)誤,需要的朋友可以參考下2016-04-04
Django框架實(shí)現(xiàn)逆向解析url的方法
這篇文章主要介紹了Django框架實(shí)現(xiàn)逆向解析url的方法,結(jié)合實(shí)例形式分析了Django逆向解析URL的原理、步驟、相關(guān)實(shí)現(xiàn)技巧與注意事項(xiàng),需要的朋友可以參考下2018-07-07
python自動(dòng)化unittest yaml使用過(guò)程解析
這篇文章主要介紹了python自動(dòng)化unittest yaml使用過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02

