[英]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.