python生成xml文件时进行格式美化
遇到的问题
在使用python的ElementTree
生成xml文件时,xml属性会被重新排序,xml文件默认无缩进,影响xml文件的可读性。
解决办法
重定向xml序列化方法。
import xml.etree.ElementTree as ET
def _serialize_xml(write, elem, qnames, namespaces,
short_empty_elements, level=0, **kwargs):
tag = elem.tag
text = elem.text
if tag is ET.Comment:
write("\t" * level + "<!--%s-->\n" % text)
elif tag is ET.ProcessingInstruction:
write("<?%s?>" % text)
else:
tag = qnames[tag]
if tag is None:
if text:
write(ET._escape_cdata(text))
for e in elem:
_serialize_xml(write, e, qnames, None, short_empty_elements=short_empty_elements, level=level+1)
else:
write("\t" * level + "<" + tag)
items = list(elem.items())
if items or namespaces:
if namespaces:
for v, k in sorted(namespaces.items(), key=lambda x: x[1]): # sort on prefix
if k:
k = ":" + k
write(" xmlns%s=\"%s\"" % (k, ET._escape_attrib(v)))
for k, v in items:
if isinstance(k, ET.QName):
k = k.text
if isinstance(v, ET.QName):
v = qnames[v.text]
else:
v = ET._escape_attrib(v)
write(" %s=\"%s\"" % (qnames[k], v))
if text or len(elem) or not short_empty_elements:
write(">\n")
if text:
write(ET._escape_cdata(text))
for e in elem:
_serialize_xml(write, e, qnames, None, short_empty_elements=short_empty_elements, level=level+1)
write("\t" * level + "</" + tag + ">\n")
else:
write(" />\n")
if elem.tail:
write(ET._escape_cdata(elem.tail))
# 重定向xml序列化方法, 以下重定向方法2选1
ET._serialize_xml = _serialize_xml
ET._serialize["xml"] = _serialize_xml
示例:
# 重定向xml序列化方法
ET._serialize_xml = _serialize_xml
def xml_test():
root = ET.Element("Root", {"level":"0"})
comment = ET.Comment("This is a test")
root.append(comment)
element = ET.Element("Element")
element.attrib = {"name":"Element", "level":"1"}
element.append(comment)
subelement = ET.SubElement(element, "SubElement")
subelement.attrib = {"name":"SubElement", "level":"2"}
root.append(element)
tree = ET.ElementTree(root)
tree.write("test.xml", encoding="utf-8", xml_declaration=True)
if __name__ == "__main__":
xml_test()
结果:
<?xml version='1.0' encoding='utf-8'?>
<Root level="0">
<!--This is a test-->
<Element name="Element" level="1">
<!--This is a test-->
<SubElement name="SubElement" level="2" />
</Element>
</Root>
未作美化时:
<?xml version='1.0' encoding='utf-8'?>
<Root level="0"><!--This is a test--><Element level="1" name="Element"><!--This is a test--><SubElement level="2" name="SubElement" /></Element></Root>