使用Python生成XML时如何调整节点属性(attributes)的排列顺序?
调整XML节点属性输出顺序的操作指引
核心原因:Python标准库xml.etree.ElementTree默认会对节点属性按字母顺序排序输出,即使传入有序字典也会被内部排序逻辑覆盖,所以需要调整序列化逻辑或者换用保序的XML处理库,以下是两种可直接落地的方案:
方案1:修改标准库序列化逻辑(无需安装额外依赖)
通过Monkey Patch替换原生ET的属性排序逻辑,保留属性插入顺序,适配Python3.7+版本(该版本后普通字典默认保存插入顺序)。
完整修改后代码如下:
import xml.etree.ElementTree as ET from xml.dom import minidom # 重写序列化方法,取消属性默认排序逻辑 def serialize_xml(write, elem, qnames, namespaces, short_empty_elements, **kwargs): tag = qnames[elem.tag] write(f'<{tag}') # 直接按属性插入顺序输出,不做字母排序 for k, v in elem.attrib.items(): write(f' {qnames[k]}="{v}"') if short_empty_elements and len(elem) == 0: write(' />') return write('>') # 子节点、文本处理逻辑和原生保持一致 for child in elem: serialize_xml(write, child, qnames, namespaces, short_empty_elements, **kwargs) if elem.text: write(elem.text) write(f'</{tag}>') # 替换原生序列化方法 ET._serializer['xml'] = serialize_xml # ------------------- 你的业务代码 ------------------- root = ET.Element("testsuites") # 构造节点时不传属性字典 suite = ET.SubElement(root, "testsuite") # 按你期望的顺序逐个添加属性 suite.set("name", "ABC") suite.set("Suit_id", "1234") suite.set("Suit_log", "Log") suite.set("Suit_total_tests", "12") # 不需要的Suit_failures属性无需添加,就不会出现在输出中 # 后续生成文件逻辑和你原有代码完全一致 xmlstr = minidom.parseString(ET.tostring(root)).toprettyxml(indent=" ") with open("Test.xml", "w", encoding='utf-8') as f: f.write(xmlstr)
方案2:使用lxml第三方库(更稳定,无侵入)
如果允许安装第三方依赖,lxml的etree模块默认保留属性插入顺序,不需要修改原生逻辑。
- 先安装依赖:
pip install lxml - 对应代码如下:
from lxml import etree root = etree.Element("testsuites") suite = etree.SubElement(root, "testsuite") # 按你期望的顺序逐个添加属性 suite.set("name", "ABC") suite.set("Suit_id", "1234") suite.set("Suit_log", "Log") suite.set("Suit_total_tests", "12") # 格式化输出XML xmlstr = etree.tostring(root, pretty_print=True, encoding='unicode', xml_declaration=True) with open("Test.xml", "w", encoding='utf-8') as f: f.write(xmlstr)
注意:XML规范本身确实不要求属性顺序,仅在你有特殊格式要求的场景下需要做上述调整,普通XML解析场景下属性顺序不影响功能使用。
内容的提问来源于stack exchange,提问作者Abhishek Rai
相关产品推荐
相关产品推荐

