[英]How do I get Python's ElementTree to pretty print to an XML file?
我正在使用 SQLite 来访问数据库并检索所需的信息。 我在 Python 2.6 版中使用 ElementTree 来创建包含该信息的 XML 文件。
import sqlite3
import xml.etree.ElementTree as ET
# NOTE: Omitted code where I acccess the database,
# pull data, and add elements to the tree
tree = ET.ElementTree(root)
# Pretty printing to Python shell for testing purposes
from xml.dom import minidom
print minidom.parseString(ET.tostring(root)).toprettyxml(indent = " ")
####### Here lies my problem #######
tree.write("New_Database.xml")
我尝试使用tree.write("New_Database.xml", "utf-8")
代替上面的最后一行代码,但它根本没有编辑 XML 的布局 - 它仍然是一团糟。
我还决定摆弄并尝试做:
tree = minidom.parseString(ET.tostring(root)).toprettyxml(indent = " ")
而不是将其打印到 Python shell,这会给出错误AttributeError: 'unicode' object has no attribute 'write' 。
When I write my tree to an XML file on the last line, is there a way to pretty print to the XML file as it does to the Python shell?
我可以在这里使用toprettyxml()
还是有其他方法可以做到这一点?
无论您的 XML 字符串是什么,您都可以通过打开一个文件来将其写入您选择的文件,然后将其写入文件。
from xml.dom import minidom
xmlstr = minidom.parseString(ET.tostring(root)).toprettyxml(indent=" ")
with open("New_Database.xml", "w") as f:
f.write(xmlstr)
有一种可能的复杂情况,尤其是在 Python 2 中,它对字符串中的 Unicode 字符既不严格也不复杂。 如果您的toprettyxml
方法返回一个 Unicode 字符串( u"something"
),那么您可能希望将其转换为合适的文件编码,例如 UTF-8。 例如,将一个写入行替换为:
f.write(xmlstr.encode('utf-8'))
我只是用indent()
函数解决了它:
xml.etree.ElementTree.indent(tree, space=" ", level=0)
将空格附加到子树以直观地缩进树。 这可用于生成打印精美的 XML 输出。 树可以是Element
或ElementTree
。space
是将为每个缩进级别插入的空白字符串,默认情况下是两个空格字符。 要在已经缩进的树内缩进部分子树,请将初始缩进级别作为level
传递。
tree = ET.ElementTree(root)
ET.indent(tree, space="\t", level=0)
tree.write(file_name, encoding="utf-8")
请注意, indent()
函数是在 Python 3.9 中添加的。
我找到了一种使用直接 ElementTree 的方法,但它相当复杂。
ElementTree 具有编辑元素文本和尾部的功能,例如element.text="text"
和element.tail="tail"
。 你必须以特定的方式使用这些来让事情排成一行,所以要确保你知道你的转义字符。
作为一个基本示例:
我有以下文件:
<?xml version='1.0' encoding='utf-8'?>
<root>
<data version="1">
<data>76939</data>
</data>
<data version="2">
<data>266720</data>
<newdata>3569</newdata>
</data>
</root>
要放置第三个元素并使其保持美观,您需要以下代码:
addElement = ET.Element("data") # Make a new element
addElement.set("version", "3") # Set the element's attribute
addElement.tail = "\n" # Edit the element's tail
addElement.text = "\n\t\t" # Edit the element's text
newData = ET.SubElement(addElement, "data") # Make a subelement and attach it to our element
newData.tail = "\n\t" # Edit the subelement's tail
newData.text = "5431" # Edit the subelement's text
root[-1].tail = "\n\t" # Edit the previous element's tail, so that our new element is properly placed
root.append(addElement) # Add the element to the tree.
要缩进内部标签(如内部数据标签),您必须将其添加到父元素的文本中。 如果你想在一个元素之后缩进任何东西(通常是在子元素之后),你把它放在尾部。
当您将其写入文件时,此代码会给出以下结果:
<?xml version='1.0' encoding='utf-8'?>
<root>
<data version="1">
<data>76939</data>
</data>
<data version="2">
<data>266720</data>
<newdata>3569</newdata>
</data> <!--root[-1].tail-->
<data version="3"> <!--addElement's text-->
<data>5431</data> <!--newData's tail-->
</data> <!--addElement's tail-->
</root>
另请注意,如果您希望程序统一使用\t
,您可能需要先将文件解析为字符串,然后将所有缩进空格替换为\t
。
此代码是在 Python3.7 中编写的,但在 Python2.7 中仍然有效。
安装bs4
pip install bs4
使用此代码进行漂亮的打印:
from bs4 import BeautifulSoup
x = your xml
print(BeautifulSoup(x, "xml").prettify())
如果要使用 lxml,可以通过以下方式完成:
from lxml import etree
xml_object = etree.tostring(root,
pretty_print=True,
xml_declaration=True,
encoding='UTF-8')
with open("xmlfile.xml", "wb") as writter:
writter.write(xml_object)`
如果您看到 xml 命名空间,例如py:pytype="TREE"
,可能需要在创建xml_object
之前添加
etree.cleanup_namespaces(root)
这对于您的代码中的任何调整都应该足够了。
将本安德森的答案视为一个函数。
def _pretty_print(current, parent=None, index=-1, depth=0):
for i, node in enumerate(current):
_pretty_print(node, current, i, depth + 1)
if parent is not None:
if index == 0:
parent.text = '\n' + ('\t' * depth)
else:
parent[index - 1].tail = '\n' + ('\t' * depth)
if index == len(parent) - 1:
current.tail = '\n' + ('\t' * (depth - 1))
所以在不漂亮的数据上运行测试:
import xml.etree.ElementTree as ET
root = ET.fromstring('''<?xml version='1.0' encoding='utf-8'?>
<root>
<data version="1"><data>76939</data>
</data><data version="2">
<data>266720</data><newdata>3569</newdata>
</data> <!--root[-1].tail-->
<data version="3"> <!--addElement's text-->
<data>5431</data> <!--newData's tail-->
</data> <!--addElement's tail-->
</root>
''')
_pretty_print(root)
tree = ET.ElementTree(root)
tree.write("pretty.xml")
with open("pretty.xml", 'r') as f:
print(f.read())
我们得到:
<root>
<data version="1">
<data>76939</data>
</data>
<data version="2">
<data>266720</data>
<newdata>3569</newdata>
</data>
<data version="3">
<data>5431</data>
</data>
</root>
看看vkbeautify模块。
输入和输出可以是任何组合的字符串/文件。 它非常紧凑,没有任何依赖性。
import vkbeautify as vkb
a) pretty_text = vkb.xml(your_xml_text) #return String
b) vkb.xml(your_xml_text, 'path/to/dest/file') #save in file
一个 liner(*) 从名为fname
的文件中读取、解析(一次)和漂亮地打印 XML:
from xml.dom import minidom
print(minidom.parseString(open(fname).read()).toprettyxml(indent=" "))
(* 不包括进口)
使用纯 ElementTree 和 Python 3.9+:
def prettyPrint(element):
encoding = 'UTF-8'
# Create a copy of the input element: Convert to string, then parse again
copy = ET.fromstring(ET.tostring(element))
# Format copy. This needs Python 3.9+
ET.indent(copy, space=" ", level=0)
# tostring() returns a binary, so we need to decode it to get a string
return ET.tostring(copy, encoding=encoding).decode(encoding)
如果您需要一个文件,请将最后一行替换为copy.write(...)
以避免额外的开销。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.