7
<grandParent>
    <parent>
       <child>Sam/Astronaut</child>
    </parent>
</grandParent>

I want to modify the above XML by adding another child tag inside parent tag. I'm doing something like this..

tree = ET.parse("test.xml")
a=ET.Element('parent')
b=ET.SubElement(a,"child")
b.text="Jay/Doctor"
tree.write("test.xml")

Is this the correct way of modifying the xml file? Any better way? or what else should I be taking care of in the above code?

nick01
  • 333
  • 1
  • 8
  • 19
  • 1
    Did you run that code? What were the results? – Robᵩ Jul 31 '14 at 20:58
  • When I run this code now, I don't see the XML getting modified. I thought I did see it getting modified earlier and I had received the results required but thought its not correct way hence posted. – nick01 Jul 31 '14 at 21:12
  • 1
    When you ask questions on SO, it is good to include all the relevant information, including the expected and observed results of whatever code you post. Otherwise, good question. – Robᵩ Jul 31 '14 at 21:15
  • Alright captain! Will keep that in mind. – nick01 Jul 31 '14 at 21:18

1 Answers1

10

Your code creates a whole new tree and adds Jay to it. You need to connect Jay to the existing tree, not to a new one.

Try this:

import xml.etree.ElementTree as ET

tree = ET.parse("test.xml")
a = tree.find('parent')          # Get parent node from EXISTING tree
b = ET.SubElement(a,"child")
b.text = "Jay/Doctor"
tree.write("test.xml")

If you want to search for a particular child, you could do this:

import xml.etree.ElementTree as ET
tree = ET.parse("test.xml")
a = tree.find('parent')
for b in a.findall('child'):
    if b.text.strip() == 'Jay/Doctor':
        break
else:
    ET.SubElement(a,"child").text="Jay/Doctor"
tree.write("test.xml")

Notice a.findall() (similar to a.find(), but returns all of the named elements). xml.etree has very limited search criteria. You might consider using lxml.etree and its .xpath() method.

Blinxen
  • 807
  • 2
  • 13
  • 26
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • thanks this works.I think I could use find() to verify no child similar to one I am about to enter exists. To avoid duplicates. – nick01 Jul 31 '14 at 21:13
  • actually, how do I execute the find command inside the parent tag? Two parent tags could have same children but a single parent should not have duplicates.. – nick01 Jul 31 '14 at 21:19
  • that worked for me. This might be all I need from ElementTree. I will look into lxml.etree if I need more capability I guess. Thanks much! – nick01 Jul 31 '14 at 21:36
  • Well I guess I spoke too soon - I am now having name spaces in the parent tag and my find all method now has a problem ... AttributeError: 'NoneType' object has no attribute 'findall' How do I handle this? – nick01 Jul 31 '14 at 22:17
  • 1
    I am doing something like this. spaces={'xmlns':'http://maven.apache.org/POM/4.0.0', 'xsi':'http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation':'http://maven.apache.org/xsd/maven-4.0.0.xsd'} using spaces in the find all method.. find all('module', namespaces=spaces) – nick01 Jul 31 '14 at 22:30
  • That sounds like a new question. – Robᵩ Jul 31 '14 at 22:31
  • Here it is: http://stackoverflow.com/questions/25070180/working-with-namespace-while-parsing-xml-using-elementtree – nick01 Jul 31 '14 at 22:47