1

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.

jetmas
  • 49
  • 1
  • 7
  • 1
    Forgive me, but you improperly mentioned attributes in your title and post when you really meant elements: `elementvalue`. You are trying to add new elements, `Gate`, `Parent0`, and `Parent1` and values not attributes and values. Sorry this seems picky but Python code changes slightly between the two. – Parfait Jul 29 '15 at 18:39
  • Thanks, @Parfait. Yes, you are correct! I usually get confused by both. But yes, I was referring to element, not an attribute – jetmas Jul 29 '15 at 18:41

1 Answers1

1

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())
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
  • Thanks a bunch, @Anand! I was actually looking for the SubElement functionality, I just wasn't able to find it. I thought it was append for some reason. This makes is so easy! Thanks again – jetmas Jul 29 '15 at 18:33
  • how would you take this and save it to XML document? I tried getting the print statement you wrote and writing it on a new document, but it doesn't work. Is there a way to do so? – jetmas Jul 29 '15 at 19:20