jetmas
jetmas

Reputation: 49

Insert XML Value/Element with Python

I've been looking all over for a solution to adding an element/value to a current XML file. So let's assume I have the following XML File:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Node>
        <Name>Sprinkler</Name>
        <Type>Blah</Type>
        <Prob>0.82</Prob>
    </Node>
    <Node>
        <Name>Rain</Name>
        <Type>Bleh</Type>
        <Prob>0.23</Prob>
    </Node>
    <Node>
        <Name>Cloudy</Name>
        <Type>Bluh</Type>
        <Prob>0.71</Prob>
    </Node>
</Root>

Now, my goal is, given a CSV file, I want to add new elements and values per Node. Let's say that my CSV contains something like this:

Cloudy,Or,Sprinkler,Rain
Sprinkler,And,Rain
Rain,Or,Sprinkler,Cloudy

I was able to read the CSV without a problem, my problem is adding new elements, 'Parent0' and 'Parent1'(If any), so that the output looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Node>
        <Name>Sprinkler</Name>
        <Type>Blah</Type>
        <Prob>0.82</Prob>
        <Gate>And</Gate>
        <Parent0>Rain</Parent0>
    </Node>
    <Node>
        <Name>Rain</Name>
        <Type>Bleh</Type>
        <Prob>0.23</Prob>
        <Gate>Or</Gate>
        <Parent0>Sprinkler</Parent0>
        <Parent1>Cloudy</Parent1>
    </Node>
    <Node>
        <Name>Cloudy</Name>
        <Type>Bluh</Type>
        <Prob>0.71</Prob>
        <Gate>Or</Gate>
        <Parent0>Sprinkler</Parent0>
        <Parent1>Rain</Parent1>
    </Node>
</Root>

So far I have written the following in Python:

import xml.etree.ElementTree as ET

xml = ET.parse('XML.xml')
for row in xml.iterfind('Node'):
    i = 1
    for item in csvFile:
        row.append('<Gate>'+item[1]+'</Gate>\n')
        if i != 1:
            for x in xrange(0, len(item):
                if row.findtext('Name') == item[x]:
                    row.append('<Parent0>'+item[x]+'</Parent0>\n')
        else:
            i = 0

On my code it will all go to Parent0 for now, but I wanted to see how it is possible to do the append, without deleting everything? I have a heard of lxml and minidom but not sure how these work. If I am able to do it using xml.etree.ElementTree, that would be fantastic.

Upvotes: 1

Views: 5731

Answers (1)

Anand S Kumar
Anand S Kumar

Reputation: 90889

An easy way to do this would be to use ElementTree.SubElement() to create the elements, it would automatically add those elements to the end of the parent node, which is passed in as argument.

Example/Demo -

>>> import xml.etree.ElementTree as ET
>>> import csv
>>> with open('test.csv','r') as f:
...     cfiles = list(csv.reader(f))
...
>>> xml = ET.parse('XML.xml')
>>> for row in xml.iterfind('.//Node'):
...     name = row.find('./Name').text
...     for i in cfiles:
...         if i[0] == name:
...             j = 1
...             while j < len(i):
...                 if j == 1:
...                     g = ET.SubElement(row,'Gate')
...                     g.text = i[j]
...                 elif j == 2:
...                     g = ET.SubElement(row,'Parent0')
...                     g.text = i[j]
...                 elif j == 3:
...                     g = ET.SubElement(row,'Parent1')
...                     g.text = i[j]
...                 j += 1
...
>>> print(ET.tostring(xml.getroot()).decode())
<Root>
    <Node>
        <Name>Sprinkler</Name>
        <Type>Blah</Type>
        <Prob>0.82</Prob>
    <Gate>And</Gate><Parent0>Rain</Parent0></Node>
    <Node>
        <Name>Rain</Name>
        <Type>Bleh</Type>
        <Prob>0.23</Prob>
    <Gate>Or</Gate><Parent0>Sprinkler</Parent0><Parent1>Cloudy</Parent1></Node>
    <Node>
        <Name>Cloudy</Name>
        <Type>Bluh</Type>
        <Prob>0.71</Prob>
    <Gate>Or</Gate><Parent0>Sprinkler</Parent0><Parent1>Rain</Parent1></Node>
</Root>

Here above , cfiles is a list I have previously created from the csv file.


For writing the xml to a new document, do -

with open('newxml.xml','w') as of:
    of.write(ET.tostring(xml.getroot()).decode())

Upvotes: 1

Related Questions