Search code examples
pythonxmlelementtreepretty-print

How to create XML file using Python?


I would like to create an XML file. I tried it but the format looks bad, it only shows in one line.

Here is it:

import xml.etree.cElementTree as ET
root = ET.Element("data")
doc = ET.SubElement(root, "status", date="20210123")

ET.SubElement(doc, "name", name="john").text = "some value1"
ET.SubElement(doc, "class", name="abc").text = "some vlaue2"

tree = ET.ElementTree(root)
tree.write("FILE.xml")

The output is:

<data><status date="20210123"><name name="john">some value1</name><class name="abc">some vlaue2</class></status></data>

But my expectation output is:

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

<data>
     <status>
          <name name="john">some value1</name>
          <class name="abc">some vlaue2</class>
     </status>
</data>

Anyone can give me an idea, please. I really appreciated it. Thank you


Solution

  • You need to

    1. Use ET.tostring() to get your xml as a string
    2. Use xml.dom.minidom to get a DOM object from the string
    3. Use toprettyxml() of DOM object to get the xml as formatted string
    4. Add encoding information to the xml declaration part by simply splitting and concating the formatted string
    5. Write the string to a file

    Code:

    import xml.etree.cElementTree as ET
    import xml.dom.minidom
    
    m_encoding = 'UTF-8'
    
    root = ET.Element("data")
    doc = ET.SubElement(root, "status", date="20210123")
    ET.SubElement(doc, "name", name="john").text = "some value1"
    ET.SubElement(doc, "class", name="abc").text = "some vlaue2"
    
    dom = xml.dom.minidom.parseString(ET.tostring(root))
    xml_string = dom.toprettyxml()
    part1, part2 = xml_string.split('?>')
    
    with open("FILE.xml", 'w') as xfile:
        xfile.write(part1 + 'encoding=\"{}\"?>\n'.format(m_encoding) + part2)
        xfile.close()
    

    Output file

    <?xml version="1.0" encoding="UTF-8"?>
    
    <data>
        <status date="20210123">
            <name name="john">some value1</name>
            <class name="abc">some vlaue2</class>
        </status>
    </data>