Python排序XML中System节点下Extents时忽略其他节点的问题
解决XML中System节点下Extents节点排序并保留非Extents节点位置的问题
问题分析
你的代码报错核心原因是:未区分Extents和非Extents节点,直接对System的所有子节点执行排序逻辑时,非Extents节点找不到LineSize子节点,调用find("LineSize").attrib["Value"]会抛出AttributeError。同时原代码逻辑错误,遍历System的子节点并尝试排序子节点的子节点,完全不符合需求。
解决方案
我们需要将System节点下的子节点分为三类:前置非Extents节点、所有Extents节点、后置非Extents节点,仅对Extents节点排序,再将三部分按原有顺序拼接,保证非Extents节点的位置不变。
修正后的代码
import xml.etree.ElementTree as ET my_tree = ET.parse('test.xml') root = my_tree.getroot() # 遍历根节点下的所有子节点 for node in root: # 匹配XML中的system标签(注意大小写,实际标签为大写则改为node.tag == "System") if node.tag == "system": before_extents = [] extents_list = [] after_extents = [] has_found_extents = False # 分离System节点的子节点为三类 for child in node: if child.tag == "extents": has_found_extents = True extents_list.append(child) else: if not has_found_extents: # 未遇到Extents前的非Extents节点,保留在前置列表 before_extents.append(child) else: # 已遇到Extents后的非Extents节点,保留在后置列表 after_extents.append(child) # 对Extents节点按LineSize的Value值降序排序 extents_list.sort(key=lambda x: int(x.find("LineSize").attrib["Value"]), reverse=True) # 重新组合System的子节点列表 node[:] = before_extents + extents_list + after_extents # 写入结果文件,指定编码和XML声明避免乱码 my_tree.write('test_ordered.xml', encoding='utf-8', xml_declaration=True)
代码说明
- 节点分离:遍历System的子节点,将非Extents节点分为前置(第一个Extents之前)和后置(最后一个Extents之后)两类,Extents节点单独收集
- 排序逻辑:仅对Extents节点排序,排序依据是
LineSize节点的Value属性转换为整数后的值,降序排列 - 节点重组:将前置非Extents、排序后的Extents、后置非Extents按顺序拼接,替换原System的子节点列表
- 大小写兼容:如果XML标签大小写不固定,可以将判断条件改为
node.tag.lower() == "system"和child.tag.lower() == "extents"
效果验证
针对你提供的示例XML,处理后:
- name为
aa的system节点:graphics节点位置不变,extents节点按Value降序排列(id=2在前,id=1在后) - name为
bb的system节点:extents节点按Value降序排列(id=3在前,id=4在后),random1节点位置不变
内容的提问来源于stack exchange,提问作者TheDataPanda
相关产品推荐
相关产品推荐

