Python 将 XML 解析为缺少元素的 CSV

标签 python xml csv parsing

第一次尝试使用 Python 将 XML 解析为 CSV。当我有多个客户并且他们没有相同的子元素时,我需要一些帮助。当客户没有子元素时,我希望 csv 文件列填充为“空”。我希望“空”成为占位符,以便将存在的值填充到正确的列中。

发生情况的示例,请注意第二行中的数据(假定位于邮政编码、街道和数字字段中)如何被挤入之前未找到任何值的列中。 ! /image/Ik5J1.jpg !

这是我想要做的一个示例,您会看到“空”只是一个占位符: ! /image/uByjT.jpg !

这是我的Python代码:

import xml.etree.ElementTree as ET
import csv

tree = ET.parse(r'C:\Documents\cat.xml')
root = tree.getroot()

#Open the file for writing

CustomerData = open(r'C:\Users\Kris\Documents\customerdata.csv', 'w')

#Create header row object

header_row = []

#Create the csv writer object

csvwriter = csv.writer(CustomerData)

#Set count to 0

count = 0

#Find tags and text

for node in tree.iter('Customer'):
data = []
if count == 0:
    for customerid in node.iter('Id_Customer'):
        customer = customerid.tag
        header_row.append(customer)
    for segmentid in node.iter('Segment'):
        segment = segmentid.tag
        header_row.append(segment)
    for event in node.iter('Event'):
        for natureid in event.iter('Nature'):
            nature = natureid.tag
            header_row.append(nature)
    for event2 in node.iter('Event'):
        for Extrainfoid in event2.iter('Extrainfo'):
            extrainfo = Extrainfoid.tag
            header_row.append(extrainfo)
    for address in node.iter('Address'):
        for zipcode in address.iter('zipcode'):
            zipcd = zipcode.tag
            header_row.append(zipcd)
    for address in node.iter('Address'):
        for streetname in address.iter('street'):
            street = streetname.tag
            header_row.append(street)
    for address in node.iter('Address'):
        for number in address.iter('number'):
            num = number.tag
    csvwriter.writerow(header_row)
    count = count + 1

for customerid in node.iter('Id_Customer'):
    customertxt = customerid.text
    data.append(customertxt)
for segmentid in node.iter('Segment'):
    segmenttxt = segmentid.text
    data.append(segmenttxt)
for event in node.iter('Event'):
    for natureid in event.iter('Nature'):
        naturetxt = natureid.text
        data.append(naturetxt)
for event2 in node.iter('Event'):
    for Extrainfoid in event2.iter('Extrainfo'):
        extrainfotxt = Extrainfoid.text
        data.append(extrainfotxt)
for address in node.iter('Address'):
    for zipcode in address.iter('zipcode'):
        zipcdtxt = zipcode.text
        data.append(zipcdtxt)
for address in node.iter('Address'):
    for streetname in address.iter('street'):
        streettxt = streetname.text
        header_row.append(streettxt)
for address in node.iter('Address'):
    for number in address.iter('number'):
        numtxt = number.text
        data.append(numtxt)
csvwriter.writerow(data)

CustomerData.close()    

这是一个 XML 代码示例,它与我的代码类似,但具有不同的元素。这不是我使用的真正的 xml 代码,只是一个客户如何拥有其他客户没有的多个元素的示例。请注意,在我使用 xml 文件的实际过程中, header 和所有内容都在我的 csv 文件中正确显示,当该元素实际上没有该特定客户的值时,我只需要创建一个“空”。

<CAT>
 <Header>...</Header>
 <Add>...</Add>
 <Customer>
  <Id_Customer>xyz1</Id_Customer>
  <Segment>abc1</Segment>
  <Event>
   <Nature>info1</Nature>
   <Extrainfo>info2</Extrainfo>
  </Event>
</Customer>
<Customer>
 <Id_Customer>zzwy</Id_Customer>
 <Segment>c2</Segment>
 <Adress>
  <zipcode>77098</zipcode>
  <street>belaire drive</street>
  <number>5</number>
 </Adress>
</Customer>

...

最佳答案

您可以创建一个包含您想要的所有映射的列表。尝试搜索每个,如果不存在,捕获 AttributeError 并为其存储一个空值:

import xml.etree.ElementTree as ET
import csv

fields = [
    ('Id_Customer', 'Id_Customer'),
    ('Segment', 'Segment'),
    ('Nature', 'Event/Nature'),
    ('Extrainfo', 'Event/Extrainfo'),
    ('zipcode', 'Adress/zipcode'),
    ('street', 'Adress/street'),
    ('number', 'Adress/number')]

tree = ET.parse('cat.xml')
root = tree.getroot()

with open(r'customerdata.csv', 'wb') as f_customerdata:
    csv_customerdata = csv.DictWriter(f_customerdata, fieldnames=[field for field, match in fields])
    csv_customerdata.writeheader()

    for node in tree.iter('Customer'):
        row = {}

        for field_name, match in fields:
            try:
                row[field_name] = node.find(match).text
            except AttributeError as e:
                row[field_name] = ''

        csv_customerdata.writerow(row)

为您提供一个输出 CSV 文件,其中包含:

Id_Customer,Segment,Nature,Extrainfo,zipcode,street,number
xyz1,abc1,info1,info2,,,
zzwy,c2,,,77098,belaire drive,5

此方法还使用 DictWriter() 而不是标准 csv 编写器。这使得按名称分配值变得更容易。

<小时/>

为了处理每个客户的多个地址条目,您首先需要自动创建每个条目的最大额外列数。然后在访问元素时,使用 findall() 获取每个元素:

import xml.etree.ElementTree as ET
import csv

extra_columns = 2

fields = [
    ('Id_Customer', 'Id_Customer', 1),
    ('Segment', 'Segment', 1),
    ('Nature', 'Event/Nature', 1),
    ('Extrainfo', 'Event/Extrainfo', 1),
    ('zipcode', 'Adress/zipcode', extra_columns),
    ('street', 'Adress/street', extra_columns),
    ('number', 'Adress/number', extra_columns)]

tree = ET.parse('cat.xml')
root = tree.getroot()

# Auto create the header from fields
fieldnames = []

for field, match, cols in fields:
    fieldnames.append(field)

    if cols > 1:
        fieldnames.extend(["{}{}".format(field, x+2) for x in range(extra_columns)])

with open(r'customerdata.csv', 'wb') as f_customerdata:
    csv_customerdata = csv.DictWriter(f_customerdata, fieldnames=fieldnames)
    csv_customerdata.writeheader()

    for node in tree.iter('Customer'):
        row = {}

        for field_name, match, cols in fields:
            if cols > 1:
                for index, el in enumerate(node.findall(match)):
                    try:
                        if index:
                            row["{}{}".format(field_name, index+1)] = el.text
                        else:
                            row[field_name] = el.text

                    except AttributeError as e:
                        row[field_name] = ''
            else:
                try:
                    row[field_name] = node.find(match).text
                except AttributeError as e:
                    row[field_name] = ''

        csv_customerdata.writerow(row)

所以你的标题现在看起来像:

Id_Customer,Segment,Nature,Extrainfo,zipcode,zipcode2,zipcode3,street,street2,street3,number,number2,number3

关于Python 将 XML 解析为缺少元素的 CSV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46959107/

相关文章:

C++ : read csv file with fgetc and separate words on semicolon ";"

python - 精确匹配一个词组

shell - 用于将 IPv6 地址转换为数字(或字符串)的大型 CSV 文件的脚本

python - 如何将 Django 模块添加到 pydiction 字典?

php - 如何使用 YouTube API 获取视频时长?

java - 重写 Xerces 实现以通过 XMLInputFactory 创建 XMLEventReader

java - 如何使用 url 作为 StringReader 的 InputSource

Powershell - 如何将 laSTLogon 转换为天数

python - 如何使用 tweepy 在 Twitter 上获取关注者数量

python - 解释(并使用)Fabric 本地命令的输出