1

This is very similar to this question: Insert XML document into existing XML with Python, but I need to be able to insert many different xml documents with many attributes into deeply nested portions of an existing XML document where the subelements have the same name. Here is a MWE without attributes to clutter things up

The main document I need to insert elements into:

<a><b1><array><c1></c1><c1></c1><c1></c1></array></b1><b2></b2></a>

The XML I want to insert:

<f><g><h2></h2><h1></h1></g></f>

The output I want:

<a>
   <b1>
      <array>
         <c1 />
         <c1>
            <f>
               <g>
                  <h2 />
                  <h1 />
               </g>
            </f>
         </c1>
         <c1 />
      </array>
   </b1>
   <b2 />
</a>

My current python code:

import xml.etree.ElementTree as ET 

top_xml = ET.fromstring("<a><b1><array><c1></c1></array></b1><b2></b2></a>")
bottom_xml = ET.fromstring("<f><g><h2></h2><h1></h1></g></f>")

#want to insert `bottom_xml` under the <c1> tag

here is where I get stuck. ElementTree.insert and ElementTree.append appear to work on the top element. Ive seen other answers using ElementTree.subelement to add simple xml elements to subelements, but manually recreating the xml structure of bottom_xml when it could be hundreds of lines deep seems to be unwieldy.

1 Answer 1

1

Using find to get the node you want to insert into:

 top_xml = ET.fromstring("<a><b1><array><c1></c1></array></b1><b2></b2></a>")

 bottom_xml = ET.fromstring("<f><g><h2></h2><h1></h1></g></f>")

 insert_node = top_xml.find('.//c1')

 insert_node.append(bottom_xml)

Then the result is:

In [31]: print(ET.tostring(top_xml).decode())
<a><b1><array><c1><f><g><h2 /><h1 /></g></f></c1></array></b1><b2 /></a>

This works since the object extracted with find is still part of the root object and whatever mutations you make are reflected back to the root object.

More about xpath expressions supported with find are found here

If you want anything more advanced I suggest using lxml

Edit

Based on your question, you want to insert on the second element, you can use [position]

For example:

insert_node = top_xml.find('.//c1[2]')

Result:

In [73]: print(ET.tostring(top_xml).decode())
<a><b1><array><c1 /><c1><f><g><h2 /><h1 /></g></f></c1><c1 /></array></b1><b2 /></a>
Sign up to request clarification or add additional context in comments.

2 Comments

This is perfect aside from one thing I'm realizing my MWE is missing. If I had multiple elements named c1, is there a way to still use .find? say if my data structure was <a><b1><array><c1></c1><c1></c1><c1></c1></array></b1><b2></b2></a> ? looking at the documentation for find, it seems I would only be able to append elements to the first one. I went ahead and edited the MWE for my question.
@motherbrain I added an Edit to address your question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.