【问题标题】:Convert Deeply Nested XML to CSV in Python [duplicate]在 Python 中将深度嵌套的 XML 转换为 CSV [重复]
【发布时间】:2016-09-19 15:19:02
【问题描述】:

我是 Python 新手,听说它是解析相当大的 XML 文件 (150MB) 的最佳方法之一。我不知道如何遍历标签并仅提取 <hw><defunit> 标签,因为它嵌套得很深。

我有一些 XML 格式如下,我需要使用 Python 从中提取“hw”和“defunit”标签并将它们转换为 .csv 格式。

<?xml version="1.0" encoding="UTF-8"?>
<dps-data xmlns="urn:DPS2-metadata" project="SCRABBLELARGE" guid="7d6b7164fde1e064:34368a61:14306b637ab:-8000--4a25ae5c-c104-4c7a-bba5-b434dd4d9314">
    <superentry xmlns="urn:COLL" xmlns:d="urn:COLL" xmlns:e="urn:IDMEE" e:id="u583c10bfdbd326ba.31865a51.12110e76de1.-336">
        <entry publevel="1" id="a000001" e:id="u583c10bfdbd326ba.31865a51.12110e76de1.-335">
            <hwblk>
                <hwgrp>
                    <hwunit>
                        <hw>aa</hw>
                        <ulsrc>edsh</ulsrc>
                    </hwunit>
                </hwgrp>
            </hwblk>
            <datablk>
                <gramcat publevel="1" id="a000001.001">
                    <pospgrp>
                        <pospunit>
                            <posp value="noun" />
                        </pospunit>
                    </pospgrp>
                    <sensecat id="a000001.001.01" publevel="1">
                        <defgrp>
                            <defunit>
                                <def>volcanic rock</def>
                            </defunit>
                        </defgrp>
                    </sensecat>
                </gramcat>
            </datablk>
        </entry>
    </superentry>
  </dps-data>

我希望看到的 .csv 格式很简单:

hw, defunit
aa, volcanic rock

【问题讨论】:

  • 什么是重复元素:&lt;superentry&gt;&lt;entry&gt;?通常最好发布前几个重复的 XML 项,以便我们了解树。
  • @Parfait 抱歉,我只被允许这么多代码。 是两个重复的元素,是的!

标签: python xml csv


【解决方案1】:

这个怎么样:

from xml.dom import minidom

xmldoc = minidom.parse('your.xml')
hw_lst = xmldoc.getElementsByTagName('hw')
defu_lst = xmldoc.getElementsByTagName('def')

with open('your.csv', 'a') as out_file:
    for i in range(len(hw_lst)):
        out_file.write('{0}, {1}\n'.format(hw_lst[i].firstChild.data, defu_lst[i].firstChild.data)) 

【讨论】:

  • 此脚本在一定程度上可以工作,但在脚本运行时会导致我的计算机无法使用。然后我在中途遇到一个 ascii 错误,它没有完成整个文件。不过谢谢!
  • @Powellellogram,你的 xml 文件中有非 ascii 字符吗?然后你需要相应地处理它们。运行此程序时,您是否检查过您的计算机死机的原因?您是否尝试调试并单步执行代码以查看可能出现的问题?如果没有,我建议你这样做。
【解决方案2】:

考虑一下XSLT,这种XML 转换语言可以将源.xml 文件操作为各种最终用途结构,包括.csv 等文本文件,在&lt;xsl:output&gt; 中指定method="text"

Python 的 lxml 模块可以运行 XSLT 1.0 脚本。下面假设 &lt;entry&gt; 标签及其子标签使用不同的数据重复。并且必须在 xsl 中处理两个未声明的名称空间。此外,XSLT 在处理较小的 XML 时往往非常有效,但会因计算机环境而异。

XSLT 脚本(另存为 .xsl 以供下文引用)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
               xmlns:ns1="urn:DPS2-metadata" xmlns="urn:COLL">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" method="text"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/ns1:dps-data/ns1:superentry">
   <xsl:text>hw,defunit</xsl:text><xsl:text>&#xa;</xsl:text>
   <xsl:apply-templates select="ns1:entry"/>
</xsl:template>

<xsl:template match="ns1:entry" namespace="urn:COLL">    
   <xsl:value-of select="descendant::ns1:hw" namespace="urn:COLL"/><xsl:text>,</xsl:text>
   <xsl:value-of select="descendant::ns1:defunit" namespace="urn:COLL"/>
   <xsl:text>&#xa;</xsl:text>
</xsl:template>

Pyton脚本

import lxml.etree as ET

// LOAD XML AND XSL SOURCES
xml = ET.parse('Input.xml')
xsl = ET.parse('XSLTScript.xsl')

// TRANSFORM SOURCE
transform = ET.XSLT(xsl)
newdom = transform(xml)

// SAVE AS .CSV
with open('Output.csv'), 'wb') as f:
    f.write(newdom)

# hw,defunit
# aa,volcanic rock

【讨论】:

  • 这似乎将每个单词都写入了 csv 文件,但我遇到了一个问题,即每一行或每一列都没有换行符或逗号。
  • 你运行脚本了吗? xslt 包含逗号和换行实体,&amp;#xa&lt;xsl:text&gt; 标签中。
【解决方案3】:

lxml 库具有非常强大的 XML 解析能力,可用于遍历 XML 树以搜索特定元素。

from lxml import etree

with open(r'path/to/xml', 'r') as xml:
    text = xml.read()
tree = lxml.etree.fromstring(text)
row = ['', '']
for item in tree.iter('hw', 'def'):
    if item.tag == 'hw':
       row[0] = item.text
    elif item.tag == 'def':
       row[1] = item.text

line = ','.join(row)

with open(r'path/to/csv', 'a') as csv:
     csv.write(line + '\n')

如何构建 CSV 文件很大程度上取决于偏好,但我在上面提供了一个简单的示例。如果有多个&lt;dps-data&gt; 标签,您可以先提取这些元素(可以使用上面显示的相同tree.iter 方法完成),然后将上述逻辑应用于每个标签。

编辑:我应该指出,这个特定的实现将整个 XML 文件读入内存。如果您一次处理一个 150mb 的文件,这应该不是问题,但这只是需要注意的事情。

【讨论】:

  • 使用此脚本时出现错误“只能将列表(而不是“str”)连接到列表中。我知道我需要将 row 的值转换为字符串,但不确定如何!
  • 您能发布完整的错误信息吗?此外,我意识到脚本应该搜索def,而不是defunit,因为def 标记包含您想要的文本。
  • C:\Users\...\Local\Programs\Python\Python35-32\python.exe C:/Users/.../PycharmProjects/xmltocsv2/xmltocsv.py Traceback (most recent call last): File "C:/Users/mbpowell/PycharmProjects/xmltocsv2/xmltocsv.py", line 18, in &lt;module&gt; csv.write(row + '\n') TypeError: can only concatenate list (not "str") to list 是我收到的错误消息。
  • 我发现了我的错误并编辑了代码。问题是当我调用','.join(row) 时,我没有将结果分配给变量,这意味着生成的字符串永远不会保存以供以后使用。请改用新的line 变量。
  • 是的,我也尝试了该变量修复。然后脚本运行没有错误,但 csv 文件没有写入任何内容。
猜你喜欢
  • 2020-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-03
  • 2018-10-27
  • 2021-05-17
  • 2019-09-24
相关资源
最近更新 更多