【问题标题】:Python XML to CSV help for novicePython XML to CSV 帮助新手
【发布时间】:2021-11-04 22:24:52
【问题描述】:

我有一个很大的 XML 文件。我在下面包含了一个擦洗过的 sn-p。下面的result-size是文件调用<row>的XML文件中的元素个数。

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

问题 2:我需要在 Python 中做些什么不同的事情才能让 name = i.find("name").text 返回“项目 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。

还有一些更复杂的位需要函数,例如根据匹配类型和名称属性找到一个 ID 属性,并返回多个 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>

【问题讨论】:

    标签: python csv xml-parsing


    【解决方案1】:

    问题 1:如何只能在输出 CSV 文件中为 &lt;row&gt; 类型的每个 &lt;row&gt; 获取记录,而不是所有其他类型的记录? em>

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

    问题 2:我需要在 Python 中做些什么不同的事情才能让 name = i.find("name").text 返回“项目 1 的名称”?

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

    findtext匹配default=Nonenamespaces=None

    查找匹配match的第一个子元素的文本。 match 可以是标签名称或path。返回第一个匹配元素的文本内容,如果没有找到元素,则返回 default。请注意,如果匹配元素没有文本内容,则返回空字符串。 namespaces 是从命名空间前缀到全名的可选映射。传递 '' 作为前缀,将表达式中所有不带前缀的标记名称移动到给定的命名空间中。

    因此,如果缺少标记,请提供您想要的默认值。

    至于子/嵌套元素,您需要使用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

    【讨论】:

    • 谢谢!创建第二个类型为 THING-TYPE-1 和 THING-TYPE-2 的数据帧并且我在其中查找名称以返回其 ID 是否算作数据争吵?
    • 当然可以! :-) 我的意思是,只使用 pandas 来写入 CSV 是矫枉过正的。但是,如果您在写入 CSV 之前/之后使用 pandas 中的数据做其他事情,那很好;不要矫枉过正。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    相关资源
    最近更新 更多