Codr4Life
Codr4Life

Reputation: 27

Python XPath and ElementTree doesn't work if first XML parent tag is missing a child tag

I'm currently using Python to convert a XML file to CSV format by using ElementTree library and XPath. My code works will if all of the child tag exists (First name, Last name, and address) for the first parent person tag, but I receive an error message of

Child Index out of range

when the first person is missing a child tag (only first and last name exist).

What code can I write to bypass this error message? This is my first time using XPath, how can an if statement be added to this? Or should I use something else?

Here's what my XML file looks like:

<?xml version="1.0" encoding="utf-8"?>
<Members>
    <Person>
      <FirstName>JANE</FirstName>
      <LastName>DOE</LastName>
    </Person>
    <Person>
      <FirstName>JOHN</FirstName>
      <LastName>DOE</LastName>
      <Address>
        <Address1>123 Straw Street</Address1>
        <Address2></Address2>
        <City>Apple</City>
        <State>Test</State>
        <ZipCode>123456    </ZipCode>
      </Address>
    </Person>
</Members>

Current Python Code:

import  csv
import xml.etree.ElementTree as ET

tree = ET.parse("TestStack.xml")
root = tree.getroot()

xml_data_to_csv =open('OutputStack.csv','w')

Csv_writer=csv.writer(xml_data_to_csv)
list_head=[]

count=0
for element in root.findall('Person'):
    person = []

    #Get head by tag
    if count == 0:
       FirstName = element.find('FirstName').tag
       list_head.append(FirstName)

       LastName = element.find('LastName').tag
       list_head.append(LastName)

       Address = element[2].tag
       list_head.append(Address)

       Csv_writer.writerow(list_head)
       count = count +1

    #get child node
    FirstName = element.find('FirstName').text
    person.append(FirstName)

    LastName = element.find('LastName').text
    person.append(LastName)

    person.append([e.text for e in element.findall('Address//')])

    #Write List_nodes to csv
    Csv_writer.writerow(person)
xml_data_to_csv.close()

Upvotes: 1

Views: 448

Answers (1)

wp78de
wp78de

Reputation: 18950

I think the header should be predefined. I doubt that your CSV import backend accepts any format.

import  csv
import xml.etree.ElementTree as ET

tree = ET.parse("in.xml")
root = tree.getroot()

xml_data_to_csv =open('out.csv','w')

Csv_writer=csv.writer(xml_data_to_csv)
list_head=['FirstName', 'LastName', 'Address']
Csv_writer.writerow(list_head)

for element in root.findall('Person'):
    person = []

    #get child node
    FirstName = element.find('FirstName').text
    person.append(FirstName)

    LastName = element.find('LastName').text
    person.append(LastName)

    person.append([e.text for e in element.findall('Address//')])

    #Write List_nodes to csv
    Csv_writer.writerow(person)
xml_data_to_csv.close()

Otherwise, you could either handle the exception or check how many elements exist like this

if len(element) > 2:
    head_list.append(element[2])
    continue

Preinitialize the head_list = [None] * 3 #len(element), and collect the headers (as the show-up) and persons during the for-loop, then write everything at the end. I would not recommend that route.

Upvotes: 1

Related Questions