'Create zipfile: TypeError: object of type 'ElementTree' has no len()

I'm writing a xml data to the zip.

from xml.etree.ElementTree import Element, SubElement, ElementTree
from zipfile import ZipFile

def create_tree():
    root = Element("root")
    doc = SubElement(root, "doc")
    SubElement(doc, "field", name="blah").text = "text"

    return ElementTree(root)


def test():
    """
    Create zip
    """
    with ZipFile("xml.zip", 'w') as ziparc:
        element_tree = create_tree()
        ziparc.writestr("file.xml", element_tree)


if __name__ == "__main__":
    test()

An error:

File "main_test2_2.py", line 168, in test
    ziparc.writestr('file.xml', element_tree)
  File "/usr/lib/python2.7/zipfile.py", line 1127, in writestr
    zinfo.file_size = len(bytes)            # Uncompressed size
TypeError: object of type 'ElementTree' has no len()

Tell me please, how can I write xml data to the archive?



Solution 1:[1]

Write the element into a fake file (a buffer)

from xml.etree.ElementTree import Element, SubElement, ElementTree
from zipfile import ZipFile
from io import BytesIO

def create_tree():
    root = Element("root")
    doc = SubElement(root, "doc")
    SubElement(doc, "field", name="blah").text = "text"

    return ElementTree(root)


def test():
    """
    Create zip
    """
    with ZipFile("xml.zip", 'w') as ziparc:
        element_tree = create_tree()
        outbuf = BytesIO()
        element_tree.write(outbuf)
        ziparc.writestr("file.xml", outbuf.getvalue())


if __name__ == "__main__":
    test()

Edit: another user tried to suggest tostring method, but it was not complete & not working probably because first the argument has to be an Element not an ElementTree and second because of the imports (ElementTree being a package and a sub-class, there was an ambiguity).

However, I reworked the full source and it also works, I think it's even a better solution (cheers to this other user who deleted his post!)

from xml.etree.ElementTree import Element, SubElement
from zipfile import ZipFile
import xml.etree.ElementTree

def create_tree():
    root = Element("root")
    doc = SubElement(root, "doc")
    SubElement(doc, "field", name="blah").text = "text"

    return root


def test():
    """
    Create zip
    """
    with ZipFile("xml.zip", 'w') as ziparc:
        element_tree = create_tree()

        ziparc.writestr("file.xml", xml.etree.ElementTree.tostring(element_tree))


if __name__ == "__main__":
    test()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1