1

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()
1
  • It can be done with lxml, if you're interested. Commented Jun 5, 2019 at 19:23

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks wp78de, you're a genius! That worked perfectly!
how did you know that tags in the head_list would work?
@Codr4Life I just figured how I would code this any language - sometimes Python is too slick.

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.