web-dev-qa-db-fra.com

Comment écrire une déclaration XML en utilisant xml.etree.ElementTree

Je génère un document XML en Python à l'aide de ElementTree , mais la fonction tostring n'inclut pas de déclaration XML lors de la conversion en texte brut.

from xml.etree.ElementTree import Element, tostring

document = Element('outer')
node = SubElement(document, 'inner')
node.NewValue = 1
print tostring(document)  # Outputs "<outer><inner /></outer>"

J'ai besoin que ma chaîne inclue la déclaration XML suivante:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

Cependant, il ne semble pas y avoir de moyen documenté de le faire.

Existe-t-il une méthode appropriée pour rendre la déclaration XML dans une variable ElementTree?

41
Roman Alexander

Je suis surpris de constater qu'il ne semble pas y avoir de solution avec ElementTree.tostring(). Vous pouvez cependant utiliser ElementTree.ElementTree.write() pour écrire votre document XML dans un faux fichier:

from io import BytesIO
from xml.etree import ElementTree as ET

document = ET.Element('outer')
node = ET.SubElement(document, 'inner')
et = ET.ElementTree(document)

f = BytesIO()
et.write(f, encoding='utf-8', xml_declaration=True) 
print(f.getvalue())  # your XML file, encoded as UTF-8

Voir cette question . Même à ce moment-là, je ne pense pas que vous puissiez obtenir votre attribut "autonome" sans écrire vous-même au préalable.

69
wrgrs

Je voudrais utiliser lxml (voir http://lxml.de/api.html ).

Ensuite vous pouvez:

from lxml import etree
document = etree.Element('outer')
node = etree.SubElement(document, 'inner')
print(etree.tostring(document, xml_declaration=True))
20
glormph

Si vous incluez le encoding='utf8', vous aurez un en-tête XML :

xml.etree.ElementTree.tostring écrit une déclaration de codage XML avec encoding = 'utf8'

Exemple de code Python 2:

import xml.etree.ElementTree as ElementTree

tree = ElementTree.ElementTree(
    ElementTree.fromstring('<xml><test>123</test></xml>')
)
root = tree.getroot()

print 'without:'
print ElementTree.tostring(root, method='xml')
print
print 'with:'
print ElementTree.tostring(root, encoding='utf8', method='xml')

Sortie:

without:
<xml><test>123</test></xml>

with:
<?xml version='1.0' encoding='utf8'?>
<xml><test>123</test></xml>
11
Alexander O'Mara

J'ai rencontré ce problème récemment, après avoir fouillé dans le code, j'ai trouvé l'extrait de code suivant qui définit la fonction ElementTree.write

def write(self, file, encoding="us-ascii"):
    assert self._root is not None
    if not hasattr(file, "write"):
        file = open(file, "wb")
    if not encoding:
        encoding = "us-ascii"
    Elif encoding != "utf-8" and encoding != "us-ascii":
        file.write("<?xml version='1.0' encoding='%s'?>\n" % 
     encoding)
    self._write(file, self._root, encoding, {})

La réponse est donc: si vous avez besoin d'écrire l'en-tête XML dans votre fichier, définissez l'argument encoding autre que utf-8 ou us-ascii, par exemple. UTF-8

3
alijandro

Exemple de travail minimal avec l'utilisation du package ElementTree:

import xml.etree.ElementTree as ET

document = ET.Element('outer')
node = ET.SubElement(document, 'inner')
node.text = '1'
res = ET.tostring(document, encoding='utf8', method='xml').decode()
print(res)

la sortie est:

<?xml version='1.0' encoding='utf8'?>
<outer><inner>1</inner></outer>
1
Andriy

Je voudrais utiliser ET :

try:
    from lxml import etree
    print("running with lxml.etree")
except ImportError:
    try:
        # Python 2.5
        import xml.etree.cElementTree as etree
        print("running with cElementTree on Python 2.5+")
    except ImportError:
        try:
            # Python 2.5
            import xml.etree.ElementTree as etree
            print("running with ElementTree on Python 2.5+")
        except ImportError:
            try:
                # normal cElementTree install
                import cElementTree as etree
                print("running with cElementTree")
            except ImportError:
               try:
                   # normal ElementTree install
                   import elementtree.ElementTree as etree
                   print("running with ElementTree")
               except ImportError:
                   print("Failed to import ElementTree from any known place")

document = etree.Element('outer')
node = etree.SubElement(document, 'inner')
print(etree.tostring(document, encoding='UTF-8', xml_declaration=True))
0
Alessandro

Une autre option assez simple consiste à concaténer l'en-tête souhaité avec la chaîne de caractères xml comme ceci:

xml = (bytes('<?xml version="1.0" encoding="UTF-8"?>\n', encoding='utf-8') + ET.tostring(root))
xml = xml.decode('utf-8')
with open('invoice.xml', 'w+') as f:
    f.write(xml)
0
Novak

Cela fonctionne si vous voulez simplement imprimer. Obtenir une erreur lorsque j'essaie de l'envoyer dans un fichier ...

import xml.dom.minidom as minidom
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import Element, SubElement, Comment, tostring

def prettify(elem):
    rough_string = ET.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="  ")
0
Rebecca Fallon

Inclure «autonome» dans la déclaration

Je n'ai trouvé aucune alternative pour ajouter l'argument standalone dans la documentation, j'ai donc adapté la fonction ET.tosting pour le prendre comme argument.

from xml.etree import ElementTree as ET

# Sample
document = ET.Element('outer')
node = ET.SubElement(document, 'inner')
et = ET.ElementTree(document)

 # Function that you need   
 def tostring(element, declaration, encoding=None, method=None,):
     class dummy:
         pass
     data = []
     data.append(declaration+"\n")
     file = dummy()
     file.write = data.append
     ET.ElementTree(element).write(file, encoding, method=method)
     return "".join(data)
# Working example
xdec = """<?xml version="1.0" encoding="UTF-8" standalone="no" ?>"""    
xml = tostring(document, encoding='utf-8', declaration=xdec)
0
G M