131 votes

Convertir Python ElementTree en chaîne de caractères

Chaque fois que j'appelle ElementTree.tostring(e) j'obtiens le message d'erreur suivant :

AttributeError: 'Element' object has no attribute 'getroot'

Existe-t-il un autre moyen de convertir un objet ElementTree en une chaîne XML ?

TraceBack :

Traceback (most recent call last):
  File "Development/Python/REObjectSort/REObjectResolver.py", line 145, in <module>
    cm = integrateDataWithCsv(cm, csvm)
  File "Development/Python/REObjectSort/REObjectResolver.py", line 137, in integrateDataWithCsv
    xmlstr = ElementTree.tostring(et.getroot(),encoding='utf8',method='xml')
AttributeError: 'Element' object has no attribute 'getroot'

181voto

Martijn Pieters Points 271458

Element Les objets n'ont pas .getroot() méthode. Laissez tomber cet appel, et le .tostring() l'appel fonctionne :

xmlstr = ElementTree.tostring(et, encoding='utf8', method='xml')

Vous devez seulement utiliser .getroot() si vous avez un ElementTree instance .

Autres notes :

  • Cela produit un bytestring qui, dans Python 3, est le bytes type.
    Si vous devez avoir un str vous avez deux possibilités :

    1. Décode la valeur des octets résultants, à partir d'UTF-8 : xmlstr.decode("utf8")

    2. Utilice encoding='unicode' ; cela permet d'éviter un cycle de codage/décodage :

      xmlstr = ElementTree.tostring(et, encoding='unicode', method='xml')
  • Si vous voulez la valeur bytestring encodée en UTF-8 ou si vous utilisez Python 2, tenez compte du fait qu'ElementTree ne détecte pas correctement utf8 comme l'encodage XML standard, il ajoutera donc une balise <?xml version='1.0' encoding='utf8'?> déclaration. Utilisez utf-8 o UTF-8 (avec un tiret) si vous voulez éviter cela. Lorsque vous utilisez encoding="unicode" aucun en-tête de déclaration n'est ajouté.

80voto

Comment puis-je convertir ElementTree.Element à une chaîne de caractères ?

Pour Python 3 :

xml_str = ElementTree.tostring(xml, encoding='unicode')

Pour Python 2 :

xml_str = ElementTree.tostring(xml, encoding='utf-8')

Ce qui suit est compatible avec Python 2 et 3, mais ne fonctionne que pour les caractères latins :

xml_str = ElementTree.tostring(xml).decode()

Exemple d'utilisation

from xml.etree import ElementTree

xml = ElementTree.Element("Person", Name="John")
xml_str = ElementTree.tostring(xml).decode()
print(xml_str)

Sortie :

<Person Name="John" />

Explication

Malgré ce que le nom indique, ElementTree.tostring() renvoie un bytestring par défaut dans Python 2 & 3. C'est un problème dans Python 3, qui utilise Unicode pour les chaînes de caractères .

En Python 2, vous pouviez utiliser la fonction str type pour les données textuelles et binaires . Malheureusement, cette confluence de deux concepts différents peut conduire à des code fragile qui fonctionnait parfois pour l'un ou l'autre type de données, parfois pas. [...]

Pour rendre la distinction entre les données textuelles et binaires plus claire et plus prononcée, [Python 3] a fait des données textuelles et binaires des types distincts qui ne peuvent pas être mélangés à l'aveuglette. .

Source : Portage du code Python 2 vers Python 3

Si nous savons quelle version de Python est utilisée, nous pouvons spécifier l'encodage en tant que unicode o utf-8 . Sinon, si nous avons besoin d'une compatibilité avec Python 2 & 3, nous pouvons utiliser decode() à convertir dans le type correct.

À titre de référence, j'ai inclus une comparaison des éléments suivants .tostring() résultats entre Python 2 et Python 3.

ElementTree.tostring(xml)
# Python 3: b'<Person Name="John" />'
# Python 2: <Person Name="John" />

ElementTree.tostring(xml, encoding='unicode')
# Python 3: <Person Name="John" />
# Python 2: LookupError: unknown encoding: unicode

ElementTree.tostring(xml, encoding='utf-8')
# Python 3: b'<Person Name="John" />'
# Python 2: <Person Name="John" />

ElementTree.tostring(xml).decode()
# Python 3: <Person Name="John" />
# Python 2: <Person Name="John" />

Merci à Martijn Peters pour avoir souligné que le str a changé entre Python 2 et 3.


Pourquoi ne pas utiliser str() ?

Dans la plupart des scénarios, l'utilisation de str() serait le " canonique " pour convertir un objet en chaîne de caractères. Malheureusement, l'utilisation de cette méthode avec Element renvoie l'emplacement de l'objet en mémoire sous la forme d'une chaîne hexadécimale, plutôt qu'une représentation en chaîne des données de l'objet.

from xml.etree import ElementTree

xml = ElementTree.Element("Person", Name="John")
print(str(xml))  # <Element 'Person' at 0x00497A80>

4voto

Extension de réponse non-latine

Extension à La réponse de @Stevoisiak et le traitement des caractères non latins. Une seule méthode vous permettra d'afficher les caractères non latins. Cette méthode est différente pour Python 3 et Python 2.

Entrée

xml = ElementTree.fromstring('<Person Name="" />')
xml = ElementTree.Element("Person", Name="")  # Read Note about Python 2

REMARQUE : En Python 2, lors de l'appel de la fonction toString(...) l'attribution d'un code xml con ElementTree.Element("Person", Name="") soulèvera une erreur...

UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 0: ordinal not in range(128)

Sortie

ElementTree.tostring(xml)
# Python 3 (): b'<Person Name="&#53356;&#47532;&#49828;" />'
# Python 3 (John): b'<Person Name="John" />'

# Python 2 (): <Person Name="&#53356;&#47532;&#49828;" />
# Python 2 (John): <Person Name="John" />

ElementTree.tostring(xml, encoding='unicode')
# Python 3 (): <Person Name="" />             <-------- Python 3
# Python 3 (John): <Person Name="John" />

# Python 2 (): LookupError: unknown encoding: unicode
# Python 2 (John): LookupError: unknown encoding: unicode

ElementTree.tostring(xml, encoding='utf-8')
# Python 3 (): b'<Person Name="\xed\x81\xac\xeb\xa6\xac\xec\x8a\xa4" />'
# Python 3 (John): b'<Person Name="John" />'

# Python 2 (): <Person Name="" />             <-------- Python 2
# Python 2 (John): <Person Name="John" />

ElementTree.tostring(xml).decode()
# Python 3 (): <Person Name="&#53356;&#47532;&#49828;" />
# Python 3 (John): <Person Name="John" />

# Python 2 (): <Person Name="&#53356;&#47532;&#49828;" />
# Python 2 (John): <Person Name="John" />

2voto

MdV Points 11

J'ai eu le même problème dans Python 3.8 et aucune des réponses précédentes ne l'a résolu. Le problème est que ElementTree est à la fois le nom d'un module et d'une classe dans ce module. L'utilisation d'un alias rend les choses plus claires :

from xml.etree.ElementTree import ElementTree
import xml.etree.ElementTree as XET
...
ElementTree.tostring(...)  # Attribute-error
XET.tostring(...)          # Works

1voto

tobias.pal Points 71

Si vous n'en avez besoin que pour le débogage afin de voir à quoi ressemble le XML, alors au lieu de print(xml.etree.ElementTree.tostring(e)) vous pouvez utiliser dump comme ça :

xml.etree.ElementTree.dump(e)

Et cela fonctionne à la fois avec Element y ElementTree comme e Il n'y a donc pas besoin de getroot .

En la documentation de dump dit :

xml.etree.ElementTree.dump(elem)

Écrit un arbre d'éléments ou une structure d'éléments dans sys.stdout . Cette fonction ne doit être utilisée que pour le débogage.

Le format de sortie exact dépend de l'implémentation. Dans cette version, il est écrit comme un fichier XML ordinaire.

elem est un arbre d'éléments ou un élément individuel.

Modifié dans la version 3.8 : Le site dump() préserve désormais l'ordre des attributs spécifié par l'utilisateur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X