在Python中通过xml.etree.ElementTree生成的XML文件中插入换行符

60 投票
6 回答
89547 浏览
提问于 2025-04-16 00:18

我在Python中使用xml.etree.ElementTree创建了一个xml文件。然后我用

tree.write(filename, "UTF-8") 

把这个文档写到一个文件里。

但是当我用文本编辑器打开这个文件时,发现标签之间没有换行,所有内容都在一行里。

我该怎么做才能把文档写成“美观的格式”,这样在所有的xml标签之间就会有换行(希望还能有缩进等)呢?

6 个回答

13

ElementTree 并不支持漂亮打印(即格式化输出),但你可以使用其他的 XML 模块来实现。

比如说,你可以用 xml.dom.minidom.Node.toprettyxml() 这个方法:

Node.toprettyxml([indent=""[, newl=""[, encoding=""]]])

这个方法会返回一个格式化好的文档版本。这里的 indent 是用来设置缩进的字符串,默认是一个制表符;newl 是每行末尾输出的字符串,默认是换行符 \n。

你可以根据自己的需要来使用 indentnewl

下面是一个使用默认格式化字符的例子:

>>> from xml.dom import minidom
>>> from xml.etree import ElementTree
>>> tree1=ElementTree.XML('<tips><tip>1</tip><tip>2</tip></tips>')
>>> ElementTree.tostring(tree1)
'<tips><tip>1</tip><tip>2</tip></tips>'
>>> print minidom.parseString(ElementTree.tostring(tree1)).toprettyxml()
<?xml version="1.0" ?>
<tips>
    <tip>
        1
    </tip>
    <tip>
        2
    </tip>
</tips>

>>> 
94

更新 2022 - Python 3.9 及更高版本

在 Python 3.9 及以后的版本中,标准库里新增了一个功能叫做 xml.etree.ElementTree.indent

示例:

import xml.etree.ElementTree as ET

root = ET.fromstring("<fruits><fruit>banana</fruit><fruit>apple</fruit></fruits>""")
tree = ET.ElementTree(root)
    
ET.indent(tree, '  ')
# writing xml
tree.write("example.xml", encoding="utf-8", xml_declaration=True)

感谢 Michał Krzywański 提供这个更新!

在 Python 3.9 之前

我发现了一种新方法,可以避免使用新的库和重新解析 XML。你只需要把你的根元素传给这个函数(下面会解释):

def indent(elem, level=0):
    i = "\n" + level*"  "
    if len(elem):
        if not elem.text or not elem.text.strip():
            elem.text = i + "  "
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
        for elem in elem:
            indent(elem, level+1)
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i

在 xml.etree.ElementTree.Element 实例上,有一个叫做 "tail" 的属性。这个属性可以在一个节点后面设置一个字符串:

"<a>text</a>tail"

我找到了一篇2004年的链接,讲述了一个 元素库函数,它使用这个 "tail" 属性来缩进一个元素。

示例:

root = ET.fromstring("<fruits><fruit>banana</fruit><fruit>apple</fruit></fruits>""")
tree = ET.ElementTree(root)
    
indent(root)
# writing xml
tree.write("example.xml", encoding="utf-8", xml_declaration=True)

在 "example.xml" 中的结果:

<?xml version='1.0' encoding='utf-8'?>
<fruits>
    <fruit>banana</fruit>
    <fruit>apple</fruit>
</fruits>
34

我觉得最简单的解决办法是换用 lxml 这个库。在大多数情况下,你只需要把你的导入语句从 import xml.etree.ElementTree as etree 改成 from lxml import etree 或者类似的写法就可以了。

然后你可以在序列化的时候使用 pretty_print 选项:

tree.write(filename, pretty_print=True)

(这个选项在 etree.tostring 上也可以用)

撰写回答