【问题标题】:How do I parse some of the data from a large xml file?如何解析大型 xml 文件中的一些数据?
【发布时间】:2013-06-06 21:10:47
【问题描述】:

我需要从格式如下的大型 xml 文件中提取位置和半径数据,并将数据存储在二维 ndarray 中。这是我第一次使用 Python,但我找不到任何有关执行此操作的最佳方法的信息。

<species name="MyHeterotrophEPS" header="family,genealogy,generation,birthday,biomass,inert,capsule,growthRate,volumeRate,locationX,locationY,locationZ,radius,totalRadius">
0,0,0,0.0,0.0,0.0,77.0645361927206,-0.1001871531330136,-0.0013358287084401814,4.523853439106942,234.14575280979898,123.92820420047076,0.0,0.6259920275663835;
0,0,0,0.0,0.0,0.0,108.5705297969604,-0.1411462759900182,-0.001881950346533576,1.0429122163754276,144.1066875513379,72.24884428367467,0.0,0.7017581019907897;
.
.
.
</species>

编辑:按人类标准,我的意思是“大”。我没有任何记忆问题。

【问题讨论】:

  • XML 文本数据本质上是一个 CSV 文件...
  • 这个“大”是因为有很多其他你不关心的节点,因为有很多species 节点,还是因为species 节点的内容很大? (而且,“大”是一个实际问题吗?试图一次阅读所有内容会给您一个MemoryError 或将您的计算机扔进交换地狱之类的东西?)
  • 物种标签的内容就是“大”。不,这不是一个实际问题,我只是认为它可能是相关的。
  • 您的 locationX 值中包含尖括号(例如,4.5238534391069&gt;42)。这些应该如何解释?
  • 好的,如果您在每个文档中只有一个巨大的species 标签,并且“大”不足以引起问题,您可以使用 Martijn Pieters 的答案。

标签: python xml python-2.7 xml-parsing


【解决方案1】:

XML 文本值中基本上包含 CSV 数据。

使用 ElementTree 解析 XML,然后使用 numpy.genfromtxt() 将该文本加载到数组中:

from xml.etree import ElementTree as ET

tree = ET.parse('yourxmlfilename.xml')
species = tree.find(".//species[@name='MyHeterotrophEPS']")
names = species.attrib['header']
array = numpy.genfromtxt((line.rstrip(';') for line in species.text.splitlines()), 
    delimiter=',', names=names)

注意生成器表达式,使用str.splitlines() 调用;这会将 XML 元素的文本转换为一系列行,.genfromtxt() 很高兴收到。我们确实从每一行中删除了结尾的 ; 字符。

对于您的示例输入(减去 . 行),这将导致:

array([ (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 77.0645361927206, -0.1001871531330136, -0.0013358287084401814, 4.523853439106942, 234.14575280979898, 123.92820420047076, 0.0, 0.6259920275663835),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 108.5705297969604, -0.1411462759900182, -0.001881950346533576, 1.0429122163754276, 144.1066875513379, 72.24884428367467, 0.0, 0.7017581019907897)], 
      dtype=[('family', '<f8'), ('genealogy', '<f8'), ('generation', '<f8'), ('birthday', '<f8'), ('biomass', '<f8'), ('inert', '<f8'), ('capsule', '<f8'), ('growthRate', '<f8'), ('volumeRate', '<f8'), ('locationX', '<f8'), ('locationY', '<f8'), ('locationZ', '<f8'), ('radius', '<f8'), ('totalRadius', '<f8')])

【讨论】:

  • 打败我,我错过了关于导入到numpy 的部分(这意味着你可以跳过csv.reader)...
  • 不是genfromtxt,不是genfromtext吗?
  • 另外,我刚刚注意到每行末尾的分号,需要修复,否则最后一列将全部结束nan
  • 输出中剩余的nans 是因为locationX 中的尖括号,我在评论中询问了OP。从最新的编辑来看,这些似乎只是一个错字;使用编辑后的示例数据,一切正常。
  • @abarnert:现在在 OP 帖子中已修复,答案已更新以反映更改。
【解决方案2】:

如果您的 XML 就是那个 species 节点,那非常简单,Martijn Pieters 已经比我解释得更好了。

但是,如果文档中有大量 species 节点,并且它太大而无法将整个内容放入内存中,则可以使用 iterparse 而不是 parse

import numpy as np
import xml.etree.ElementTree as ET

for event, node in ET.iterparse('species.xml'):
    if node.tag == 'species':
        name = node.attr['name']
        names = node.attr['header']
        csvdata = (line.rstrip(';') for line in node.text.splitlines())
        array = np.genfromtxt(csvdata, delimiter=',', names=names)
        # do something with the array.

如果您只有一个超大的 species 节点,这将无济于事,因为即使 iterparse(或类似的解决方案,如 SAX 解析器)一次也解析一个完整的节点。您需要找到一个 XML 库,它可以让您流式传输大型节点的 text,而且在我的脑海中,我不认为任何 stdlib 或流行的第三方解析器可以这样做。

【讨论】:

  • names 也采用逗号分隔的字符串;因此,我没有打扰.split(',')
【解决方案3】:

如果文件真的很大,请使用ElementTreeSAX

如果文件不是那么大(即适合内存),minidom 可能更容易使用。

每一行似乎是一个简单的逗号分隔数字字符串,所以你可以简单地做line.split(',')

【讨论】:

  • 如果这是(看起来是)一个带有一个巨大标签的充满 CSV 数据的简单文档,那么使用 etree 或 sax 将无济于事。但是 OP 没有给我们足够的信息来做更多的事情,只是猜测是否是这种情况……
  • 我不确定这是一个单标签文件还是有很多标签带有这种数据......
猜你喜欢
  • 2011-05-09
  • 2014-06-15
  • 2014-07-11
  • 1970-01-01
  • 1970-01-01
  • 2011-03-25
  • 2020-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多