Adding a subelement iteratively with lxml

I want to add subelements iteratively e. g. from a list to a specific position of an XML path using XPath and a tag. Since in my original code I have many subnodes, I don't want to use other functions such as etree.Element or tree.SubElement.

For my provided example, I tried:

from lxml import etree

tree = etree.parse('example.xml')
root = tree.getroot()

new_subelements = ['<year></year>', '<trackNumber></trackNumber>']

destination = root.xpath('/interpretLibrary/interprets/interpretNames/interpret[2]/information')[2]

for element in new_subelements:
    add_element = etree.fromstring(element)
    destination.insert(-1, add_element)

But this doesn't work.

The initial example.xml file:

<interpretLibrary>
    <interprets>
        <interpretNames>
            <interpret>
                <information>
                    <name>Queen</name>
                    <album></album>
                </information>
            <interpret>
            <interpret>
                <information>
                    <name>Michael Jackson</name>
                    <album></album>
                </information>
            <interpret>
            <interpret>
                <information>
                    <name>U2</name>
                    <album></album>
                </information>
            </interpret>
        </interpretNames>
    </interprets>
</interpretLibrary>

The output example.xml I want to produce:

<interpretLibrary>
    <interprets>
        <interpretNames>
            <interpret>
                <information>
                    <name>Queen</name>
                    <album></album>
                </information>
            <interpret>
            <interpret>
                <information>
                    <name>Michael Jackson</name>
                    <album></album>
                </information>
            <interpret>
            <interpret>
                <information>
                    <name>U2</name>
                    <album></album>
                    <year></year>
                    <trackNumber></trackNumber>
                </information>
            <interpret>
        </interpretNames>
    </interprets>
</interpretLibrary>

Is there any better solution?

1 answer

  • answered 2022-04-28 10:52 Jack Fleeting

    Your sample xml in the question is not well formed (the closing <interpret> elements should be closed - </interpret>). Assuming you fixed that, you are almost there - though some changes are necessary:

    new_subelements = ['<year></year>', '<trackNumber></trackNumber>']
    for element in new_subelements:
        destination = root.xpath('//interpretNames/interpret[last()]/information/*[last()]')[0]
        add_element = etree.fromstring(element)
        destination.addnext(add_element)
    print(etree.tostring(root).decode())
    

    The output should be your sample expected output.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum