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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.