Search code examples
pythonxmlelementtree

Adding a new XML Element after a specific but not defined position in an exisiting XML File in python


I want to add a new XML Element to an existing XML File. The problem is that the Position varies from file to file but I want to insert my new Element always behind the last Tag of a specific element. So let's say I have X amount of <Data> Tags in the file and after the last <Data> Tag I want to create and insert a new XML Element with a <Example> Tag.

Here is my code so far:

import xml.etree.ElementTree as ET


xml_file = "example.xml"


tree = ET.parse(xml_file)
root = tree.getroot()

LastDataTag = root.findall('.//Data')[-1]

new_element = ET.Element('Example')

root.insert(LastDataTag + 1, new_element)

The Problem I see is that I don't get an integer as a return form findall, but rather a Postion within the file like this <Element 'Data' at 0x000001E99BE7A610> I get that this is obviously not working because python cant add +1 to this since it's not an integer.

Is there a way to translate this to an integer so you can work with it this way or is there another way of doing this or getting the index of the last <Data> Tag? The other posts I looked at did it the same way with the insert method but they all had a fixed index number that did not change.


Solution

  • If you're able to use lxml instead of ElementTree, it has the method addnext() that makes it much easier to add a following sibling...

    from lxml import etree
    
    xml_file = 'example_input.xml'
    tree = etree.parse(xml_file)
    
    last_data_elem = tree.findall('.//Data')[-1]
    new_element = etree.Element('Example')
    last_data_elem.addnext(new_element)
    
    tree.write('example_output.xml')
    

    If you're stuck with ElementTree, you'll first have to find the parent of the Data element so you can determine its index. Then you can use .insert() with the index plus one...

    import xml.etree.ElementTree as ET
    
    xml_file = 'example_input.xml'
    
    tree = ET.parse(xml_file)
    root = tree.getroot()
    
    last_data_elem = root.findall('.//Data')[-1]
    new_element = ET.Element('Example')
    
    for data_parent in root.findall('.//*[Data]'):
        for data_elem in data_parent.findall('Data'):
            if data_elem is last_data_elem:
                data_index = list(data_parent).index(data_elem)
                data_parent.insert(data_index + 1, new_element)
    
    tree.write('example_output.xml')