480 votes

Impression jolie de XML en Python

Quelle est la meilleure façon (ou les différentes façons) d'imprimer le XML en Python ?

419voto

Ben Noland Points 10060
import xml.dom.minidom

dom = xml.dom.minidom.parse(xml_fname) # or xml.dom.minidom.parseString(xml_string)
pretty_xml_as_string = dom.toprettyxml()

37 votes

Vous obtiendrez ainsi un fichier xml, mais notez que ce qui sort dans le nœud de texte est en fait différent de ce qui est entré - il y a de nouveaux espaces blancs sur les nœuds de texte. Cela peut vous causer des problèmes si vous vous attendez à ce que ce qui a été entré soit EXACTEMENT sorti.

54 votes

@icnivad : bien qu'il soit important de souligner ce fait, il me semble étrange que quelqu'un veuille embellir son XML si les espaces ont une certaine importance pour lui !

19 votes

Joli ! Je peux réduire cela à une ligne simple : python -c 'import sys;import xml.dom.minidom;s=sys.stdin.read();print xml.dom.minidom.parseString(s).toprettyxml()''.

182voto

1729 Points 1662

Lxml est récent, mis à jour, et inclut une jolie fonction d'impression

import lxml.etree as etree

x = etree.parse("filename")
print etree.tostring(x, pretty_print=True)

Consultez le tutoriel lxml : http://lxml.de/tutorial.html

11 votes

Le seul inconvénient de lxml est sa dépendance aux bibliothèques externes. Je pense que ce n'est pas si grave sous Windows, les bibliothèques sont empaquetées avec le module. Sous Linux, elles sont une aptitude install loin. Sous OS/X, je ne suis pas sûr.

4 votes

Sous OS X, vous avez juste besoin d'un gcc fonctionnel et de easy_install/pip.

12 votes

Lxml pretty printer n'est pas fiable et n'imprimera pas correctement votre XML dans beaucoup de cas expliqués dans FAQ lxml . J'ai arrêté d'utiliser lxml pour l'impression de jolies choses après plusieurs cas de figure qui ne fonctionnent pas (c'est-à-dire que ça ne marche pas) : Bogue n° 910018 ). Tous ces problèmes sont liés à l'utilisation de valeurs XML contenant des espaces qui doivent être préservés.

118voto

ade Points 1877

Une autre solution consiste à emprunter este indent fonction pour être utilisé avec la bibliothèque ElementTree intégrée à Python depuis la version 2.5. Voici à quoi cela ressemblerait :

from xml.etree import ElementTree

def indent(elem, level=0):
    i = "\n" + level*"  "
    j = "\n" + (level-1)*"  "
    if len(elem):
        if not elem.text or not elem.text.strip():
            elem.text = i + "  "
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
        for subelem in elem:
            indent(subelem, level+1)
        if not elem.tail or not elem.tail.strip():
            elem.tail = j
    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = j
    return elem        

root = ElementTree.parse('/tmp/xmlfile').getroot()
indent(root)
ElementTree.dump(root)

0 votes

...et ensuite utiliser lxml tostring !

2 votes

Notez que vous pouvez toujours faire tree.write([filename]) pour l'écriture dans un fichier ( tree étant l'instance d'ElementTree).

17 votes

Ce lien effbot.org/zone/element-lib.htm#prettyprint a le bon code. Le code ici a quelque chose de faux. Il doit être modifié.

48voto

nbolton Points 8244

Voici ma solution (bricolée ?) pour contourner le problème des nœuds de texte.

uglyXml = doc.toprettyxml(indent='  ')

text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)    
prettyXml = text_re.sub('>\g<1></', uglyXml)

print prettyXml

Le code ci-dessus produira :

<?xml version="1.0" ?>
<issues>
  <issue>
    <id>1</id>
    <title>Add Visual Studio 2005 and 2008 solution files</title>
    <details>We need Visual Studio 2005/2008 project files for Windows.</details>
  </issue>
</issues>

Au lieu de ça :

<?xml version="1.0" ?>
<issues>
  <issue>
    <id>
      1
    </id>
    <title>
      Add Visual Studio 2005 and 2008 solution files
    </title>
    <details>
      We need Visual Studio 2005/2008 project files for Windows.
    </details>
  </issue>
</issues>

Avis de non-responsabilité : Il y a probablement des limites.

0 votes

Merci ! C'était mon seul problème avec toutes les jolies méthodes d'impression. Ça marche bien avec les quelques fichiers que j'ai essayés.

0 votes

J'ai trouvé une solution presque identique, mais la vôtre est plus directe, en utilisant les éléments suivants re.compile avant sub (j'utilisais re.findall() deux fois, zip et un for boucle avec str.replace() ...)

3 votes

Cela n'est plus nécessaire dans Python 2.7 : la fonction toprettyxml() de xml.dom.minidom produit maintenant une sortie comme '<id>1</id>' par défaut, pour les noeuds qui ont exactement un noeud enfant texte.

23voto

roskakori Points 598

Comme d'autres l'ont souligné, lxml dispose d'une imprimante intégrée.

Sachez cependant que, par défaut, il transforme les sections CDATA en texte normal, ce qui peut avoir des résultats désagréables.

Voici une fonction Python qui préserve le fichier d'entrée et ne modifie que l'indentation (remarquez l'élément strip_cdata=False ). De plus, il s'assure que la sortie utilise l'encodage UTF-8 au lieu de l'encodage ASCII par défaut (remarquez le bouton encoding='utf-8' ) :

from lxml import etree

def prettyPrintXml(xmlFilePathToPrettyPrint):
    assert xmlFilePathToPrettyPrint is not None
    parser = etree.XMLParser(resolve_entities=False, strip_cdata=False)
    document = etree.parse(xmlFilePathToPrettyPrint, parser)
    document.write(xmlFilePathToPrettyPrint, pretty_print=True, encoding='utf-8')

Exemple d'utilisation :

prettyPrintXml('some_folder/some_file.xml')

2 votes

C'est un peu tard maintenant. Mais je pense que lxml a corrigé CDATA ? CDATA est CDATA de mon côté.

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