Sreeni Puthiyillam
Sreeni Puthiyillam

Reputation: 485

Iterating through a xml is not working in python

My XML:

<animals>
  <animal name="fox" fullname="fullfox"></animal>
  <animal name="dog" fullname="halfdog"><food>milk</food><food>rice</food><food>meat</food>   </animal>
  <animal name="cow" fullname="doublecow"><food>grass</food></animal>
  <animal name="blabla" fullname="fullbla"></animal>
</animals>

I'm trying to parse this XML to get same XML as output.

doc    = ET.parse("an.xml")
root = doc.getroot() #Returns the root element for this tree.
root_new  = ET.Element("animals") 
for child in root:
    name = child.attrib['name']
    fullname = child.attrib['fullname']

for g in root.findall("*/food"):
    animal    = ET.SubElement(root_new, "animal") 
    food     = ET.SubElement(animal, "food")   
    food.text = g.text
    animal.set("name",name)               
    animal.set("fullname",fullname) 

tree = ET.ElementTree(root_new)
tree.write(sys.stdout)

But am getting only last value

<animals>
  <animal fullname="fullbla" name="blabla"><food>milk</food></animal>
  <animal fullname="fullbla" name="blabla"><food>rice</food></animal>
  <animal fullname="fullbla" name="blabla"><food>meat</food></animal>
  <animal fullname="fullbla" name="blabla"><food>grass</food></animal>
</animals>

And food node also wrong, how to iterate exactly like my input XML?

Upvotes: 1

Views: 133

Answers (3)

light
light

Reputation: 421

You need a nested loop:

for child in root:
    name             = child.attrib['name']
    fullname         = child.attrib['fullname']
    # create "animal" here
    animal    = ET.SubElement(root_new, "animal") 
    animal.set("name",name)               
    animal.set("fullname",fullname)
    for g in child.findall("food"):
        # create "food" here
        food     = ET.SubElement(animal, "food")   
        food.text = g.text 

Upvotes: 2

aquavitae
aquavitae

Reputation: 19114

There are two problems. The first is your indentation - I assume those are meant to be nested loops. The second problem is that you're using root.findall, which means that you are getting all food items regardless of which node they are in. Try this instead:

...
for child in root:
    name = child.attrib['name']
    fullname = child.attrib['fullname']
    animal = ET.SubElement(root_new, 'animal')
    for g in child.findall("food"):
        food = ET.SubElement(animal, "food")   
        food.text = g.text
        animal.set('name', name)               
        animal.set('fullname', fullname) 

Upvotes: 1

kalyan
kalyan

Reputation: 3106

your code should look like this

doc    = ET.parse("test.xml")
root = doc.getroot() #Returns the root element for this tree.
root_new  = ET.Element("animals") 
for child in root:
    name             = child.attrib['name']
    fullname         = child.attrib['fullname']
    animal    = ET.SubElement(root_new, "animal") 
    animal.set("name",name)               
    animal.set("fullname",fullname) 

    for g in child.findall("food"):
        food = ET.SubElement(animal, "food")   
        food.text = g.text

tree = ET.ElementTree(root_new)
tree.write(sys.stdout)

Upvotes: 2

Related Questions