Python 基于xml.etree.ElementTree实现XML对比示例详解

作者:授客 时间:2022-02-24 12:25:53 

测试环境

Python 3.6

Win10

代码实现

#!/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('结点1属性:{attrib1} 值:{value1},结点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('结点1属性:{attrib1} 值:{value1},结点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中多出的子结点
           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中对应结点比xml1中对应结点多出的同名子结点
       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('子结点不一样:xml1结点(xpath:{xpath1})比xml2结点(xpath:{xpath2})多了以下子结点:\n{differences}'.format (xpath1=node1_xpath,
                                                                                                 xpath2=node2_xpath,
                                                                                                 differences='\n'.join(temp_list1)))
   # 获取xml2比xml1中多出的子结点
   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('子结点不一样:xml1结点(xpath:{xpath1})比xml2结点(xpath:{xpath2})少了以下子结点:\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 = []
   # 比较标签
   if xml_node1.tag !=  xml_node2.tag:
       result.append('标签不一样:xml1结点(xpath:{xpath1}):{tag1},xml2结点(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结点(xpath:{xpath1}):{text1},xml2结点(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结点(xpath:{xpath1}),xml2结点(xpath:{xpath2}):\n{differences}'.format (xpath1=node1_xpath,
                                                                                                 xpath2=node2_xpath,
                                                                                                 differences='\n'.join(res)))
   # 比较子结点
   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 比较模式,预留,暂时没用。目前默认 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)

测试运行

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一样')

运行结果

xml1和xml2一样 xml3和xml4不一样: 子结点不一样:xml1结点(xpath:/data/class[1])比xml2结点(xpath:/data/class[1])多了以下子结点: /data/class[1]/rangk[1] 属性不一样:xml1结点(xpath:/data/class[2]/book[2]),xml2结点(xpath:/data/class[2]/book[2]): 结点1属性:price 值:15,结点2属性:price 值:16 子结点不一样:xml1结点(xpath:/data/class[2])比xml2结点(xpath:/data/class[2])多了以下子结点: /data/class[2]/rangk[1] 子结点不一样:xml1结点(xpath:/data/class[2])比xml2结点(xpath:/data/class[2])少了以下子结点: /data/class[2]/addr[1]

来源:https://www.cnblogs.com/shouke/p/16975021.html

标签:Python,xml.etree.ElementTree,XML
0
投稿

猜你喜欢

  • python3处理含有中文的url方法

    2021-04-10 02:42:45
  • JavaScript onkeypress事件入门实例(按下或按住一个键盘按键)

    2024-05-11 10:25:13
  • tensorflow 重置/清除计算图的实现

    2023-07-23 00:41:58
  • 重新编译PLSQL中的无效对象或者指定的对象 的方法

    2009-02-26 10:41:00
  • python开发入门——set的使用

    2023-09-21 09:39:56
  • 解决Mysql 8.0.17 winx64版本安装过程中遇到的问题

    2024-01-26 12:35:33
  • 详解python中的hashlib模块的使用

    2022-02-24 17:05:37
  • Python时间戳与时间字符串互相转换实例代码

    2022-09-04 23:39:25
  • Python3如何判断三角形的类型

    2022-01-06 22:12:51
  • python3正则提取字符串里的中文实例

    2022-07-01 18:47:45
  • 如何利用数据库内容建立一个下拉式列表?

    2010-01-01 15:46:00
  • Go语言指针用法详解

    2023-08-05 17:06:36
  • python—sys模块之获取参数的操作

    2022-10-09 04:18:18
  • PHP的mysqli_rollback()函数讲解

    2023-06-12 08:58:03
  • python OpenCV学习笔记实现二维直方图

    2021-08-17 11:23:49
  • Python多进程协作模拟实现流程

    2021-07-01 17:52:38
  • vue3中给数组赋值丢失响应式的解决

    2024-05-22 10:44:41
  • vue3中使用Apache ECharts的详细方法

    2024-04-26 17:41:01
  • sql server中千万数量级分页存储过程代码

    2024-01-18 04:36:20
  • mysql 设置默认的时间值

    2024-01-18 02:49:46
  • asp之家 网络编程 m.aspxhome.com