如何在Python中不依赖pip包对比XML字符串并生成差异XML?
不依赖第三方包实现XML用户节点差异对比
直接用Python内置的xml.etree.ElementTree和xml.dom.minidom就能搞定,不需要安装任何pip包。核心思路是解析两个XML后,按name匹配用户节点,对比所有子元素的存在性和内容,只保留name和发生变化的字段(以str2的最新状态为准)。
完整实现代码
import xml.etree.ElementTree as ET import xml.dom.minidom as minidom def generate_diff_xml(str1, str2): # 解析XML字符串为Element对象 def parse_xml(xml_str): parser = ET.XMLParser(target=ET.TreeBuilder(insert_comments=True)) parser.feed(xml_str) return parser.close() root1 = parse_xml(str1) root2 = parse_xml(str2) # 建立用户name到节点的映射,快速匹配用户 users1 = {} for user in root1.findall('user'): name_elem = user.find('name') if name_elem is not None and name_elem.text: users1[name_elem.text] = user users2 = {} for user in root2.findall('user'): name_elem = user.find('name') if name_elem is not None and name_elem.text: users2[name_elem.text] = user # 创建新的根节点 new_root = ET.Element('users') # 遍历str2中的所有用户,以最新状态为基准 for name, user2 in users2.items(): user1 = users1.get(name) new_user = ET.SubElement(new_root, 'user') # 必保留name节点 name_tag = ET.SubElement(new_user, 'name') name_tag.text = name # 收集当前用户的所有子节点标签(排除name) tags2 = {elem.tag for elem in user2 if elem.tag != 'name'} all_tags = tags2.copy() if user1: tags1 = {elem.tag for elem in user1 if elem.tag != 'name'} all_tags = tags1.union(tags2) for tag in all_tags: elem1 = user1.find(tag) if user1 else None elem2 = user2.find(tag) # 情况1:节点仅在str2存在 → 新增,保留 if not elem1 and elem2: new_elem = ET.SubElement(new_user, tag) new_elem.text = elem2.text # 复制子节点(支持嵌套结构) for child in elem2: new_elem.append(child) # 情况2:节点在两者都存在,但内容/子节点不同 → 保留str2的版本 elif elem1 and elem2: # 对比文本内容 text_changed = elem1.text != elem2.text # 对比子节点 child_changed = len(elem1) != len(elem2) if not child_changed: for c1, c2 in zip(elem1, elem2): if c1.tag != c2.tag or c1.text != c2.text: child_changed = True break if text_changed or child_changed: new_elem = ET.SubElement(new_user, tag) new_elem.text = elem2.text for child in elem2: new_elem.append(child) # 格式化XML输出,让结构更清晰 def prettify_xml(elem): rough_str = ET.tostring(elem, 'utf-8') parsed = minidom.parseString(rough_str) return parsed.toprettyxml(indent=" ") return prettify_xml(new_root) # 测试示例 if __name__ == "__main__": str1 = '''<users> <user> <name>Marco</name> <height>1,76</height> <address>C:/ Far-away 34</address> <mail>marco@marco</mail> </user> </users>''' str2 = '''<users> <user> <name>Marco</name> <height>1,80</height> <address>C:/ Far-away 34</address> <mail></mail> </user> </users>''' diff_xml = generate_diff_xml(str1, str2) print(diff_xml)
关键特性说明
- 支持未知节点:不管除
name外有多少未知字段,都会自动遍历对比 - 处理嵌套结构:如果字段包含子节点,会递归对比子节点的标签和文本内容
- 以最新状态为准:完全基于str2的内容生成差异,新增、修改的字段都会保留,移除的字段则不显示
- 内置库实现:所有用到的模块都是Python标准库,无需额外安装
测试输出
运行代码后会得到符合需求的str3:
<?xml version="1.0" ?> <users> <user> <name>Marco</name> <height>1,80</height> <mail></mail> </user> </users>
内容的提问来源于stack exchange,提问作者pikubhai
相关产品推荐
相关产品推荐

