Python XML 为新手提供 CSV 帮助

Python XML to CSV help for novice

我有一个很大的 XML 文件。我在下面包含了它的一个擦洗片段。下面的result-size是文件调用<row>.

的XML文件中的元素个数

问题 1:如何在输出 CSV 文件中只获取类型 <COLLECTION-ITEM> 的每个 <row> 的记录,而不是所有其他类型的记录?我无法控制 XML 的结构。如果您在我的 Python 代码中注释掉测试值以外的所有内容,您会看到该文件正在输出 5 条记录,而我只需要 1.

问题 2:我需要在 Python 中做哪些不同的事情才能使 name = i.find("name").text 变为 return“项目 1 的名称”?

我认为只关注前两个问题的答案是公平的。我希望得到这些答案能让我走上解决这个 XML 到 CSV 问题的其余问题的道路。不过,这是大局,还有一些我需要解决的问题。给我指点书,类,只要有帮助。我只有一周左右的时间来完成这项工作。

期望的输出:

Collection item,ITEM-ID,ATTRIB-1,PERSON-TYPE-1-NAME,ATTRIB-2,PERSON-TYPE-2-NAME,RELATED-THING-1 id,RELATED-THING-2 IDs
name of Item 1,item_000001,Yes,name of person 1,Yes,name of person 2,thing_000745,"thing_000783, thing_000803"

我可以读入文件并输出一个包含我指定的列名的 CSV 文件。但是我什至无法将第一件事的名称放入 CSV 中。

然后是更复杂的位,需要函数,比如根据type和name属性匹配找到一个ID属性,return获取多个ID。请参阅 RELATED-THING-1-ID 和 RELATED-THING-2-ID。

这是我的Python(基于https://www.geeksforgeeks.org/convert-xml-to-csv-in-python/):

# -*- coding: utf-8 -*-

# Importing the required libraries
import xml.etree.ElementTree as Xet
import pandas as pd

cols = ["Collection item", "ITEM-ID", "ATTRIB-1", "PERSON-TYPE-1-NAME" ,
        "ATTRIB-2", "PERSON-TYPE-2-NAME", "RELATED-THING-1 id",
        "RELATED-THING-2 IDs"]
rows = []

# Parsing the XML file
xmlparse = Xet.parse('sample.xml')
root = xmlparse.getroot()
for i in root:
    name = i.find("name").text
    item_id = i.find("ITEM-ID").text
    attrib_1 = i.find("ATTRIB-1").text
    p1_name = i.find("PERSON-TYPE-1-NAME.result.row.name").text
    attrib_2 = i.find("ATTRIB-2").text
    p2_name = i.find("PERSON-TYPE-2-NAME.result.row.name").text
    relat_thing1_id = i.find("country").text
    relat_thing2_ids = i.find("country").text

    rows.append({"Collection item": name,
                 "ITEM-ID": item_id,
                 "ATTRIB-1": attrib_1,
                 "PERSON-TYPE-1-NAME": p1_name,
                 "ATTRIB-2": attrib_2,
                 "PERSON-TYPE-2-NAME": p2_name,
                 "RELATED-THING-1 id": relat_thing1_id,
                 "RELATED-THING-2 IDs": relat_thing2_ids
    })

df = pd.DataFrame(rows, columns=cols)

# Writing dataframe to csv
df.to_csv('output.csv')

这是XML:

<?xml version="1.0" encoding="UTF-8"?>
<result size="4321">
  <row>
    <id>3255183</id>
    <type>CONTEXT</type>
    <name>collections</name>
  </row>
  <row>
    <id>3652889</id>
    <type>COLLECTION-ITEM</type>
    <name>name of Item 1</name>
    <ITEM-ID>item_000001</ITEM-ID>
    <ATTRIB-1>Yes</ATTRIB-1>
    <PERSON-TYPE-1-NAME>
      <result size="1">
        <row>
          <id>3254728</id>
          <scopeId>3254388</scopeId>
          <type>PERSON</type>
          <name>name of person 1</name>
          <no>1</no>
        </row>
      </result>
    </PERSON-TYPE-1-NAME>
    <ATTRIB-2>Yes</ATTRIB-2>
    <PERSON-TYPE-2-NAME>
      <result size="1">
        <row>
          <id>3254403</id>
          <scopeId>3254388</scopeId>
          <type>PERSON</type>
          <name>name of person 2</name>
          <no>1</no>
        </row>
      </result>
    </PERSON-TYPE-2-NAME>
    <RELATED-THING-1>
      <result size="1">
        <row>
          <id>3391122</id>
          <scopeId>3255191</scopeId>
          <type>THING-TYPE-1</type>
          <name>thing type 1 name 1</name>
          <no>1</no>
        </row>
      </result>
    </RELATED-THING-1>
    <RELATED-THING-2>
      <result size="2">
        <row>
          <id>3255215</id>
          <scopeId>3255198</scopeId>
          <type>THING-TYPE-2</type>
          <name>thing type 2 name 1</name>
          <no>1</no>
        </row>
        <row>
          <id>3255227</id>
          <scopeId>3255198</scopeId>
          <type>THING-TYPE-2</type>
          <name>thing type 2 name 2</name>
          <no>1</no>
        </row>
      </result>
    </RELATED-THING-2>
  </row>
  <row>
    <id>3391122</id>
    <type>THING-TYPE-1</type>
    <name>thing type 1 name 1</name>
    <THING-ID>thing_000745</THING-ID>
  </row>
  <row>
    <id>3255215</id>
    <type>THING-TYPE-2</type>
    <name>thing type 2 name 1</name>
    <THING-ID>thing_000783</THING-ID>
  </row>
  <row>
    <id>3255227</id>
    <type>THING-TYPE-2</type>
    <name>thing type 2 name 2</name>
    <THING-ID>thing_000803</THING-ID>
  </row>
</result>

问题1:如何在输出的CSV文件中只为类型<COLLECTION-ITEM>的每个<row>获取一条记录,而不是所有其他类型?

添加对该标签及其内容的检查 - 如果它不是您想要的,则 continue 进行下一次迭代。或者只处理匹配的那个。

问题 2: 我的 Python 需要做哪些不同的事情才能使 name = i.find("name").text 变为 return “项目 1 的名称”?

使用 Element.findtext() 并为行中不存在的标签提供默认值。

findtext (match, default=None, namespaces=None )

Finds text for the first subelement matching match. match may be a tag name or a path. Returns the text content of the first matching element, or default if no element was found. Note that if the matching element has no text content an empty string is returned. namespaces is an optional mapping from namespace prefix to full name. Pass '' as prefix to move all unprefixed tag names in the expression into the given namespace.

因此,如果标签丢失,请提供您想要的默认值。

至于child/nested个元素,需要使用XPATHs。因此,请使用 PERSON-TYPE-1-NAME/result/row/name.

而不是 PERSON-TYPE-1-NAME.result.row.name

将这些放在一起:

for row in root:
    if row.findtext('type') != 'COLLECTION-ITEM':
        # skip if it's not what you're looking for
        continue
    name = row.findtext("name", "Missing name")
    item_id = row.findtext("ITEM-ID", "Missing item_id")
    attrib_1 = row.findtext("ATTRIB-1", "Missing attrib_1")
    p1_name = row.findtext("./PERSON-TYPE-1-NAME/result/row/name", "Missing p1_name")
    attrib_2 = row.findtext("ATTRIB-2", "Missing attrib_2")
    p2_name = row.findtext("./PERSON-TYPE-2-NAME/result/row/name", "Missing p2_name")
    relat_thing1_id = row.findtext("country", "Missing relat_thing1_id")
    relat_thing2_ids = row.findtext("country", "Missing relat_thing2_ids")
    
    rows.append({
        "Collection item": name,
        "ITEM-ID": item_id,
        "ATTRIB-1": attrib_1,
        "PERSON-TYPE-1-NAME": p1_name,
        "ATTRIB-2": attrib_2,
        "PERSON-TYPE-2-NAME": p2_name,
        "RELATED-THING-1 id": relat_thing1_id,
        "RELATED-THING-2 IDs": relat_thing2_ids
    })

print(rows)

输出:

[{'Collection item': 'name of Item 1',
  'ITEM-ID': 'item_000001',
  'ATTRIB-1': 'Yes',
  'PERSON-TYPE-1-NAME': 'name of person 1',
  'ATTRIB-2': 'Yes',
  'PERSON-TYPE-2-NAME': 'name of person 2',
  'RELATED-THING-1 id': 'Missing relat_thing1_id',
  'RELATED-THING-2 IDs': 'Missing relat_thing2_ids'}]

您可以将“Missing”作为默认值,或一个空字符串 '',为了清楚起见,我在上面放了明确的名称。

您使用 pandas 只是为了写入 CSV 还是您实际上打算使用 pandas 进行数据整理?如果只是写成CSV,那就直接用csv.DictWriter