Как получить Python ElementTree для печати в XML файле?
Фон
Я использую SQLite для доступа к базе данных и получения желаемой информации. Я использую ElementTree в Python версии 2.6 для создания 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, которая дает ошибку Объект AttributeError: 'unicode' не имеет атрибута 'write'.
Вопросы
Когда я пишу свое дерево в файл XML в последней строке, есть ли способ печатать в XML файл так же, как в оболочке Python?
Могу ли я использовать toprettyxml()
здесь или есть ли другой способ сделать это?
Ответы
Ответ 1
Независимо от вашей строки 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'))
Ответ 2
Установить bs4
pip install bs4
Используйте этот код для печати:
from bs4 import BeautifulSoup
x = your xml
print(BeautifulSoup(x, "xml").prettify())
Ответ 3
Взгляните на модуль 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
Ответ 4
Если вы хотите использовать 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)
Этого должно быть достаточно для любой адаптации вашего кода.
Ответ 5
Я нашел способ, используя прямой ElementTree, но он довольно сложный.
ElementTree имеет функции, которые редактируют текст и хвост элементов, например, element.text="text"
и element.tail="tail"
. Вы должны использовать их особым образом, чтобы все выстроилось в ряд, поэтому убедитесь, что вы знаете своих escape-персонажей.
В качестве основного примера:
У меня есть следующий файл:
<?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 attribute
addElement.tail = "\n" # Edit the element tail
addElement.text = "\n\t\t" # Edit the element text
newData = ET.SubElement(addElement, "data") # Make a subelement and attach it to our element
newData.tail = "\n\t" # Edit the subelement tail
newData.text = "5431" # Edit the subelement text
root[-1].tail = "\n\t" # Edit the previous element 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 text-->
<data>5431</data> <!--newData tail-->
</data> <!--addElement tail-->
</root>
Еще одно замечание: если вы хотите, чтобы программа равномерно использовала \t
, вы можете сначала проанализировать файл как строку и заменить все пробелы для отступов на \t
.
Этот код был сделан в Python3.7, но все еще работает в Python2.7.