Как получить 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.