web-dev-qa-db-fra.com

Comment puis-je obtenir ElementTree de Python pour imprimer assez dans un fichier XML?

Contexte

J'utilise SQLite pour accéder à une base de données et récupérer les informations souhaitées. J'utilise ElementTree dans Python version 2.6 pour créer un fichier XML avec ces informations.

Code

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")

Tentatives

J'ai essayé d'utiliser tree.write("New_Database.xml", "utf-8") à la place de la dernière ligne de code ci-dessus, mais cela n'a pas du tout modifié la disposition du XML - c'est toujours un gâchis.

J'ai également décidé de tripoter et j'ai essayé de faire:
tree = minidom.parseString(ET.tostring(root)).toprettyxml(indent = " ")
au lieu d'imprimer ceci dans le shell Python, ce qui donne l'erreur AttributeError: l'objet 'unicode' n'a pas d'attribut 'écriture'.

Des questions

Lorsque j'écris mon arborescence dans un fichier XML sur la dernière ligne, existe-t-il un moyen d'imprimer correctement dans le fichier XML comme dans le shell Python?

Puis-je utiliser toprettyxml() ici ou existe-t-il une autre façon de procéder?

27
Kimbluey

Quelle que soit votre chaîne XML, vous pouvez l'écrire dans le fichier de votre choix en ouvrant un fichier pour l'écriture et en écrivant la chaîne dans le fichier.

from xml.dom import minidom

xmlstr = minidom.parseString(ET.tostring(root)).toprettyxml(indent="   ")
with open("New_Database.xml", "w") as f:
    f.write(xmlstr)

Il existe une complication possible, en particulier dans Python 2, qui est à la fois moins strict et moins sophistiqué sur les caractères Unicode dans les chaînes. Si votre méthode toprettyxml remet une chaîne Unicode (u"something"), vous souhaiterez peut-être le convertir en un encodage de fichier approprié, tel que UTF-8. Par exemple. remplacez la ligne d'écriture par:

f.write(xmlstr.encode('utf-8'))
35
Jonathan Eunice

Installer bs4

pip install bs4

Utilisez ce code pour imprimer:

from bs4 import BeautifulSoup

x = your xml

print(BeautifulSoup(x, "xml").prettify())
3
RJX

Si l'on veut utiliser lxml, cela pourrait se faire de la manière suivante:

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)`

Si vous voyez des espaces de noms xml, par exemple py:pytype="TREE", on pourrait vouloir ajouter avant la création de xml_object

etree.cleanup_namespaces(root) 

Cela devrait être suffisant pour toute adaptation dans votre code.

3
Nick

Jetez un œil au module vkbeautify .

L'entrée et la sortie peuvent être des chaînes/fichiers dans n'importe quelle combinaison. Il est très compact et n'a aucune dépendance.

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 
2
vadimk

J'ai trouvé un moyen d'utiliser ElementTree droit, mais c'est assez complexe.

ElementTree possède des fonctions qui modifient le texte et la queue des éléments, par exemple, element.text="text" et element.tail="tail". Vous devez les utiliser d'une manière spécifique pour aligner les choses, alors assurez-vous de connaître vos personnages d'échappement.

Comme exemple de base:

J'ai le fichier suivant:

<?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>

Pour placer un troisième élément dans et le garder joli, vous avez besoin du code suivant:

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.

Pour mettre en retrait les balises internes (comme la balise de données interne), vous devez l'ajouter au texte de l'élément parent. Si vous voulez indenter quelque chose après un élément (généralement après les sous-éléments), vous le mettez dans la queue.

Ce code donne le résultat suivant lorsque vous l'écrivez dans un fichier:

<?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>

Autre remarque, si vous souhaitez que le programme utilise uniformément \t, vous souhaiterez peut-être d'abord analyser le fichier sous forme de chaîne et remplacer tous les espaces pour les indentations par \t.

Ce code a été créé en Python3.7, mais fonctionne toujours en Python2.7.

1
Ben Anderson