3

I am writing multiple xml files in python by looping over lists of strings. Suppose I have:

from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring

parent = Element('parent')
child = SubElement(parent, 'child')
f = open('file.xml', 'w')
document = ElementTree(parent)
l = ['a', 'b', 'c']
for ch in l:
    child.text = ch
    document.write(f, encoding='utf-8', xml_declaration=True)

The output:

<?xml version='1.0' encoding='utf-8'?>
<parent><child>a</child></parent><?xml version='1.0' encoding='utf-8'?>
<parent><child>b</child></parent><?xml version='1.0' encoding='utf-8'?>
<parent><child>c</child></parent>

Desired output:

<?xml version='1.0' encoding='utf-8'?>
<parent>
<child>a</child>
<child>b</child>
<child>c</child>
</parent>

I only want the xml declaration to appear one time, at the top of the file. Probably should write the declaration to the file before the loop, but when I attempt that, I get empty elements. I do not want to do this:

f.write('<?xml version='1.0' encoding='utf-8'?>')

How to write just to xml declaration to the file?

Edit: Desired output

3 Answers 3

6

You need to add the SubItems to the tree before writing the file. In your code you overwritten the same element and wrote the entire XML document in every iteration of the loop.

Also, your XML syntax is missing a top-level "root" element to be valid.

from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring

root = Element('root')

l = ['a', 'b', 'c']
for ch in l:
    parent = SubElement(root,'parent')
    child = SubElement(parent, 'child')
    child.text = ch

document = ElementTree(root)
document.write('file.xml', encoding='utf-8', xml_declaration=True)

and the output will be:

<?xml version='1.0' encoding='utf-8'?>
<root>
  <parent><child>a</child></parent>
  <parent><child>b</child></parent>
  <parent><child>c</child></parent>
</root> 
Sign up to request clarification or add additional context in comments.

Comments

1

I am not familiar with Python's XML libraries, but let's take a step back. If you do what you want, your output will not be valid XML. XML must have exactly one root element.

So, you could have:

<?xml version='1.0' encoding='utf-8'?>
<uberparent>
<parent><child>a</child></parent>
<parent><child>b</child></parent>
<parent><child>c</child></parent>
</uberparent>

Supposing you're creating a Google site map, for example: their schema says that the root element is "urlset".

Comments

0

This is technically doable by just setting a bool() flag on xml_declaration:

parent = Element('parent')
child = SubElement(parent, 'child')
f = open('file.xml', 'w')
document = ElementTree(parent)
l = ['a', 'b', 'c']
# use enumerate to have (index, element) pair, started from 0
for i, ch in enumerate(l):
    child.text = ch
    # Start index=0, since bool(0) is Fale, and bool(1..n) is True
    # the flag will be offset
    document.write(f, encoding='utf-8', xml_declaration=bool(not i))
f.close()

Updated:

Since OP has realised the desired ouput is incorrect in syntax, and changed the requirement, here is the normal way to deal with xml:

from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring

parent = Element('parent')
f = open('file.xml', 'w')
document = ElementTree(parent)
l = ['a', 'b', 'c']
for ch in l:
    child = SubElement(parent, 'child')
    child.text = ch
document.write(f, encoding='utf-8', xml_declaration=True)
f.close()

1 Comment

Although as a side note, just like what @Amirshk mentioned, this is not a valid xml syntax

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.