Search code examples
pythonxmlelementelementtreexml-attribute

How to add multiple XML element to an existing text in a XML file with python


I have a problem with some values not being declared as XML elements in my XML files. But for further processing, I need them to be an element. Example:

<A>
<B id="254">
    <C>Lore</C>
    <D>9</D> 
    12.34
</B>
<B id="255">
    <C>Ipsum</C>
    <D>125</D> 
    23.45
</B>
<E/>
<F id="256">
    <G>Lore Ipsum
        <E>79</E> 
        34.56
    </G>
</F>
</A>

In the end, the XML file should look similar to this:

<A>
<B id="254">
    <C>Lore</C>
    <D>9</D> 
    <Z>12.34</Z> 
</B>
<B id="255">
    <C>Ipsum</C>
    <D>125</D> 
    <Z>23.45</Z>
</B>
<E/>
<F id="256">
    <G>Lore Ipsum
        <E>79</E>
        <Y>34.56</Y> 
    </G>
</F>
</A>

I looked in various python documentation but only found a way to add a new element with a value.


Solution

  • You can do this with the build in functionality xml.etree.ElementTree:

    import xml.etree.ElementTree as ET
    
    tree = ET.parse('Start_extended.xml')
    root = tree.getroot()
    # ET.dump(root)
    
    def set_z(elem, val):
        # set value to the new tagz or y
        elem.text = val
        return elem
    
    def catch_tail(root, b_elem):
        # read tail text
        tail_text = b_elem.tail
        return tail_text
    
    def reset_tail(root, b_elem):
        # remove tail
        b_elem.tail = '\n'
        return b_elem.tail
    
    
    for elem in root.iter():
        #print(elem.tag)
        if elem.tag == 'B':
            z = ET.SubElement(elem, 'Z')
        if elem.tag == 'G':
            y = ET.SubElement(elem, 'Y') 
        if elem.tag == "D":
            val = catch_tail(root, elem)
            reset_tail(root, elem)
        if elem.tag == "Z":
            set_z(elem, val)
        if elem.tag == "E":
            val1 = catch_tail(root, elem)
            reset_tail(root, elem)
        if elem.tag == "Y":
            set_z(elem, val1)
           
    ET.dump(root)
    
    tree.write("new.xml", encoding='utf-8', xml_declaration=True)
    

    Output:

    <?xml version="1.0" encoding="utf-8"?>
    <A>
      <B id="254">
        <C>Lore</C>
        <D>9</D>
        <Z>12.34</Z>
      </B>
      <B id="255">
        <C>Ipsum</C>
        <D>125</D>
        <Z>23.45</Z>
      </B>
      <E />
      <F id="256">
        <G>Lore Ipsum 
        <E>79</E>
        <Y>34.56</Y>
        </G>
      </F>
    </A>