Reputation: 1046
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
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