Olga Olga - 3 months ago 23
Python Question

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?

Answer

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()
Comments