【发布时间】:2010-06-22 17:12:47
【问题描述】:
我在 python 中使用 xml.etree.ElementTree 创建了一个 xml 文件。然后我使用
tree.write(filename, "UTF-8")
将文档写入文件。
但是当我使用文本编辑器打开文件名时,标签之间没有换行符。一切都是一条大线
如何以“漂亮打印”的格式写出文档,以便在所有 xml 标记之间有新行(希望有缩进等)?
【问题讨论】:
我在 python 中使用 xml.etree.ElementTree 创建了一个 xml 文件。然后我使用
tree.write(filename, "UTF-8")
将文档写入文件。
但是当我使用文本编辑器打开文件名时,标签之间没有换行符。一切都是一条大线
如何以“漂亮打印”的格式写出文档,以便在所有 xml 标记之间有新行(希望有缩进等)?
【问题讨论】:
我找到了一种避免新库和重新解析 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 年的链接,讲述了一个 Element Library Functions 使用这个“尾巴”来缩进一个元素。
例子:
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>
【讨论】:
os.linesep 以便在记事本(Windows)中正确获取新行。
lxml 中的节点时,新元素没有设置尾部空白。因此,即使使用 lxml 包,您的解决方案也是必要的。
我认为最简单的解决方案是切换到lxml 库。在大多数情况下,您只需将导入从 import xml.etree.ElementTree as etree 更改为 from lxml import etree 或类似的。
然后您可以在序列化时使用pretty_print 选项:
tree.write(filename, pretty_print=True)
(也可通过etree.tostring 获得)
【讨论】:
pretty_print 选项有什么作用? documentation 说它“启用格式化的 XML”,但是格式化 XML 是什么意思?
ElementTree 中没有漂亮的打印支持,但您可以使用其他 XML 模块。
例如xml.dom.minidom.Node.toprettyxml():
Node.toprettyxml([indent=""[, newl=""[, encoding=""]]])返回文档的精美打印版本。 indent 指定缩进字符串,默认为制表符; newl 指定在每行末尾发出的字符串,默认为 \n。
使用indent 和newl 来满足您的要求。
使用默认格式字符的示例:
>>> 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>
>>>
【讨论】:
1 和 2 ;在 xml 中很重要)?
ET.tostring(main, encoding='utf8', method='xml').decode() 时,它会从标题中删除encoding="utf-8"。解决了toprettyxml(encoding='utf8')
不使用外部库,您可以通过将每个元素的tail属性设置为'\n',轻松实现输出中每个XML标签之间的换行。
您还可以在此处指定换行符后的制表符数。但是,在 OP 的用例选项卡中,使用外部库可能更容易实现,或者参见 Erick M. Sprengel 的回答。
我在尝试使用 python 中的 xml.etree.ElementTree 修改 xml 文档时遇到了同样的问题。就我而言,我正在解析 xml 文件,清除某些元素(使用 Element.clear()),然后将结果写回文件。
对于我已清除的每个元素,在输出文件中其标记后没有新行。
ElementTree 的 Element.clear() 文档指出:
此函数移除所有子元素,清除所有属性,并将文本和尾部属性设置为无。
这让我意识到元素的文本和尾部属性是确定输出格式的方式。就我而言,我能够将已清除元素的这些属性设置为与清除之前相同的值。对于根 xml 元素的第一级子元素,此尾部值最终为 '\n\t',选项卡数表示输出中显示的选项卡数。
【讨论】:
According to this thread 你最好的选择是安装pyXml 并将其用于prettyprint ElementTree xml 内容(因为默认情况下 ElementTree 在 Python 中似乎没有漂亮的打印机):
import xml.etree.ElementTree as ET
from xml.dom.ext.reader import Sax2
from xml.dom.ext import PrettyPrint
from StringIO import StringIO
def prettyPrintET(etNode):
reader = Sax2.Reader()
docNode = reader.fromString(ET.tostring(etNode))
tmpStream = StringIO()
PrettyPrint(docNode, stream=tmpStream)
return tmpStream.getvalue()
【讨论】: