alkey
alkey

Reputation: 1046

Python easier way to insert new items into XML sub sub elements using ElementTree

I am editing a config file and would like to add new sub elements into the structure. The problem I am having is that in the config file the sub elements have the same name and I have not found a way to find the index the insert location with a .find command. An example of the config file is here:

<?xml version="1.0" encoding="utf-8"?>

<ConfigurationFile>
  <Configuration ItemName="Parent1">
    <Category ItemName="Parent2">
      <Category ItemName="Parent3">
        <Category ItemName="ChildLevelToAdd">
          <Option ItemName="x" ValueType="6">5</Option>
          <Option ItemName="z" ValueType="6">0</Option>
          <Category ItemName="ChildCategory">
            <Option ItemName="a" ValueType="1"></Option>
            <Option ItemName="b" ValueType="2"></Option>
            <Option ItemName="c" ValueType="3">
            </Option>
            </Category>
        </Category>
      </Category>
</Category>

I am trying to add a new "ChildToAdd" category and everything that falls below it.

I have tried the following code to index, but it seems it is only able to locate first child elements:

a = root.find('Configuration') #It is only possible to find sub-elements of the root
b = root.find('Category') #These generate a none type

The best way I have found to insert the new category element is using:

root[0][0][0].insert(0,ET.Element("Category", ItemName = "NewChild"))

And then when I want to add options to this newly created category I use:

root[0][0][0][0].insert(0,ET.Element("NewOption", ItemName = "NewVal", ValueType ="NewType"))

This seems like a very untidy way to do this. I am wondering if there are any cleaner methods to find and specify the insertion point for the new subsubelement (category) and its future sub-elements (options)?

Upvotes: 1

Views: 96

Answers (1)

har07
har07

Reputation: 89295

Use XPath expression in the form of .//element_name to find element anywhere within context node (the root element in this case). For example, the following should return first instance of <Category> element, anywhere within root :

root.find('.//Category') 

You can also find element by its attribute value using XPath. For example, the following should return <Category> element where ItemName attribute value equals "Parent3" :

root.find('.//Category[@ItemName="Parent3"]')

ElementTree supports some other XPath syntax as documented in here.


I'd also suggest to store your new element in a variable so that you can add child element to it later without having to query the XML again :

c = ET.Element("Category", ItemName = "NewChild")
c.insert(0,ET.Element("NewOption", ItemName = "NewVal", ValueType ="NewType"))

p = root.find('.//Category[@ItemName="Parent3"]')
p.insert(0, c)

Upvotes: 1

Related Questions