Veejay
Veejay

Reputation: 565

Adding a subelement to a subelement lxml

I am using lxml in an attempt to to output the following xml code:

<annotation>
    <folder>images</folder>
    <filename>IMG_8111.JPG</filename>
    <size>
        <width>400</width>
        <height>400</height>
    </size>
    <segmented>0</segmented>
    <object>
        <name>Bottle</name>
        <bndbox>
            <xmin>16</xmin>
            <ymin>71</ymin>
            <xmax>390</xmax>
            <ymax>323</ymax>
        </bndbox>
    </object>
</annotation>

Im using this tutorial to learn how to implement lxml for my needs. The issue I am facing is that my desired output has subelements to subelements. For instance - <annotation> is my main element, and then <folder>, <filename> and <size> are subelements, but then, <height> and <width>' are subelements to the` subelements. How do I make this happen with lxml. I have the following so far:

from lxml import etree
import xml.etree.cElementTree as ET


root = etree.Element("annotation")
etree.SubElement(root, "folder").text = "Child 1"
etree.SubElement(root, "filename").text = "Child 2"
size = etree.SubElement(root, "size").text = "Child 3"
etree.SubElement(size, "width").text = "Child 4"


with open ('xmltree.xml', 'wb') as f:
    f.write(etree.tostring(root, pretty_print = True))

But it throws the following error:

 etree.SubElement(size, "width").text = "Child 4"
TypeError: Argument '_parent' has incorrect type (expected lxml.etree._Element, got str)

Please help me out on what I am doing wrong and how to proceed.

Upvotes: 0

Views: 5343

Answers (2)

Jared Goguen
Jared Goguen

Reputation: 9010

In order for size = etree.SubElement(root, "size").text = "Child 3" to be evaluated as you expect it to be, it would have to be interpreted as:

(size = etree.SubElement(root, "size")).text = "Child 3"

In Python, you can't perform an assignment in an expression. Instead, the way Python interprets this is:

size = "Child 3"
etree.SubElement(root, "size").text = "Child 3"

You could rewrite your code using two separate lines to achieve your desired result:

size = etree.SubElement(root, "size")
size.text = "Child 3"

After looking through the lxml API, it does not appear to be a way way to both create an element and assign a value to the text attribute in a single line.

Upvotes: 2

Gadolfo
Gadolfo

Reputation: 21

Your variable size has type string because it has "child 3" value. You should do:

size = etree.SubElement(root,"size")
size.text = "child 3" 
etree.SubElement(size, "width").text="child 4"

Upvotes: 1

Related Questions