Use xml.etree.ElementTree to print nicely formatted xml files [duplicate]
Asked Answered
W

2

67

I am trying to use xml.etree.ElementTree to write out xml files with Python. The issue is that they keep getting generated in a single line. I want to be able to easily reference them so if it's possible I would really like to be able to have the file written out cleanly.

This is what I am getting:

<Language><En><Port>Port</Port><UserName>UserName</UserName></En><Ch><Port>IP地址</Port><UserName>用户名称</UserName></Ch></Language>

This is what I would like to see:

<Language>
    <En>
        <Port>Port</Port>
        <UserName>UserName</UserName>
    </En>
    <Ch>
        <Port>IP地址</Port>
        <UserName>用户名称</UserName>
    </Ch>
</Language>
Weixel answered 1/7, 2013 at 10:30 Comment(5)
This is not a true duplicate: The other question leaves the possibility to use any XML library. This question asks specifically for a solution when you are already working with the built-in element tree library. Imho it makes perfect sense to ask this question specifically for this library, because it is apparently a missing feature!?Olcott
you can use a function like the one i found here: effbot.org/zone/element-lib.htm#prettyprintBriefcase
@Olcott When someone report, the other people will re-report, just to follow something. I'm from Colombia, so sorry for my bad english.Treacle
Related: Python Bug Tracker - Issue report for Pretty Printing; and GitHub - proposed pull request.Montage
You can check my answer here: https://mcmap.net/q/25555/-pretty-printing-xml-in-python. As of Python 3.9 there will be a new indent function built-in.Dynameter
N
74

You can use the function toprettyxml() from xml.dom.minidom in order to do that:

def prettify(elem):
    """Return a pretty-printed XML string for the Element.
    """
    rough_string = ElementTree.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="\t")

The idea is to print your Element in a string, parse it using minidom and convert it again in XML using the toprettyxml function.

Source: http://pymotw.com/2/xml/etree/ElementTree/create.html

Nocti answered 1/7, 2013 at 10:35 Comment(7)
This adds extra lines. Not sure I'd call that pretty.Sim
For a large file though this requires reparsing the whole XML. hmm...Inseparable
@steve: Not only does that add another line, the data is processed like this: convert the XML tree to string, convert it back to an XML tree, and then convert it back to a string. That's not pretty, that's completely out of the question.Sergius
At least it works out of the box with a normal Python installation.Homburg
@RaúlSalinas-Monteagudo Not for my Python installation. Unfortunately I have the displeasure of working in an environment where lxml, bs4, xmltodict, stdio, numpy, etc. don't exist and can't be easily installed. Sorry just ranting... Now if only I could find a one-line solution for an out-dated and unsupported Python 2.7...Vharat
This answer does not refer to xml.etree.Kimbro
@Kimbro ElementTree is imported from xml.etreeWavelength
G
24

You could use the library lxml (Note top level link is now spam) , which is a superset of ElementTree. Its tostring() method includes a parameter pretty_print - for example:

>>> print(etree.tostring(root, pretty_print=True))
<root>
  <child1/>
  <child2/>
  <child3/>
</root>
Goulet answered 1/7, 2013 at 10:39 Comment(6)
"pretty_print=True" does not work for me, and I do not whyGilda
etree.tostring(root, pretty_print=True).decode() works!Gilda
Yes. But lxml does not support default namespace very well.Kyphosis
It supportds namespaces much better than other libraries :) Also that link is now dead and a spamGoulet
This answer does not refer to xml.etree.Kimbro
@Kimbro No but it does tell you how to get a prettyprint without changing much code - only need to change the import rather than using minidom which has a totally different APIGoulet

© 2022 - 2024 — McMap. All rights reserved.