2

I was following the documentation of how to use xml.etree to parse data from an xml file, but it seems that important information seem to be missing.

I am using the same example:

<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank>1</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank>4</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank>68</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>

and for each country I am trying to get the year associated to that country. I tried the following code:

import sys
import xml.etree.ElementTree as ET

tree = ET.parse(sys.argv[1])
root = tree.getroot()
for child in root:
    print(child.tag, child.attrib. child.get('year')) # or child['year'], or child.find('year').text

but none of these seem to work. How do I extract the value for year for each of the three countries?

Expected output:

country {'name': 'Liechtenstein'} 2008
country {'name': 'Singapore'} 2011
country {'name': 'Panama'} 2011

Addendum:

I found a way to get the 'year':

import sys
import xml.etree.ElementTree as ET

tree = ET.parse(sys.argv[1])
root = tree.getroot()
for child in root:
    for elem in list(child):
        if elem.tag == 'year':
            print(child.tag, child.attrib, elem.text)

Is there no simpler way?

4 Answers 4

1

Which python version is used? For python 3.8 it would be:

def get_value(el):
    return el.text if el is not None else None

root = ET.fromstring(xml)

for country in root.findall('country'):
    year = get_value(country.find('year'))
    rank = get_value(country.find('rank'))
    neighbors = country.findall('neighbor')
    neighbor_names = [neighbor.get('name') for neighbor in neighbors]
    print(year, rank, neighbor_names)
Sign up to request clarification or add additional context in comments.

Comments

1

You're in the right direction :) Try child.findall()

Some notes regarding your attempts:

  • child.get(attribute_name) returns the attribute named attribute_name of the element child
  • child[] expects an index (i.e. an integer)

2 Comments

What output did you get when using child.find()? If only the first element, then the method works as expected in the documentation: find(match, namespaces=None) Finds the first subelement matching match. match may be a tag name or a path.
Sorry, seems to work. I was pretty sure that gave an error message before ...
1

Have a look at the Element.iter() method.

The following code snippet will give you the desired output:

import sys
import xml.etree.ElementTree as ET

tree = ET.parse(sys.argv[1])
root = tree.getroot()

for child in root.iter('country'):
    for grandchild in child.iter('year'):
        print(child.attrib, grandchild.text)

Comments

1
import xml.etree.ElementTree as ET


xml = '''<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank>1</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank>4</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank>68</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>'''

root = ET.fromstring(xml)
data = {c.attrib['name']: c.find('year').text for c in root.findall('.//country')}
print(data)

output

{'Liechtenstein': '2008', 'Singapore': '2011', 'Panama': '2011'}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.