解析/读取大型XML文件,占用内存最少

时间:2014-01-16 14:05:28

标签: ruby xml-parsing

我有一个非常大的XML文件(300mb),格式如下:

<data>
 <point>
  <id><![CDATA[1371308]]></id>
  <time><![CDATA[15:36]]></time>
 </point>
 <point>
  <id><![CDATA[1371308]]></id>
  <time><![CDATA[15:36]]></time>
 </point>
 <point>
  <id><![CDATA[1371308]]></id>
  <time><![CDATA[15:36]]></time>
 </point>
</data>

现在我需要阅读它并遍历point节点为每个节点做一些事情。目前我正在和Nokogiri这样做:

require 'nokogiri'
xmlfeed = Nokogiri::XML(open("large_file.xml"))
xmlfeed.xpath("./data/point").each do |item|
  save_id(item.xpath("./id").text)
end

然而,这并不是非常有效,因为它解析了整个拥抱的一切,因此创造了巨大的内存占用(几GB)。

有没有办法在块中执行此操作?如果我没有弄错的话,可能会被称为流媒体?

修改

使用nokogiris sax解析器的建议答案可能没问题,但是当每个point中有多个节点需要从中提取内容并以不同方式处理时,它会变得非常混乱。我宁愿选择一次访问一个point,然后处理它,然后继续下一个&#34;忘记&#34;而不是返回大量的条目供以后处理。以前的。

3 个答案:

答案 0 :(得分:6)

鉴于这个鲜为人知(但很棒)gist使用Nokogiri的Reader界面,你应该能够做到这一点:

Xml::Parser.new(Nokogiri::XML::Reader(open(file))) do
  inside_element 'point' do
    for_element 'id' do puts "ID: #{inner_xml}" end
    for_element 'time' do puts "Time: #{inner_xml}" end
  end
end

有人应该把它变成宝石,也许是我;)

答案 1 :(得分:2)

使用Nokogiri::XML::SAX::Parser(事件驱动的解析器)和Nokogiri::XML::SAX::Document

require 'nokogiri'

class IDCollector < Nokogiri::XML::SAX::Document
  attr :ids

  def initialize
    @ids = []
    @inside_id = false
  end

  def start_element(name, attrs)
    # NOTE: This is simplified. You need some kind of stack manipulations
    #                           (push in start_element / pop in end_element)
    #    to correctly pick `.//data/point/id` elements.
    @inside_id = true if name == 'id'
  end
  def end_element(name)
    @inside_id = false
  end

  def cdata_block string
    @ids << string if @inside_id
  end
end

collector = IDCollector.new
parser = Nokogiri::XML::SAX::Parser.new(collector)
parser.parse(File.open('large_file.xml'))
p collector.ids # => ["1371308", "1371308", "1371308"]

根据the documentation

  

Nokogiri::XML::SAX::Parser:是一个读取它的SAX样式解析器   输入,因为它认为必要。

如果您需要更多控制文件输入,也可以使用Nokogiri::XML::SAX::PushParser

答案 2 :(得分:0)

如果你使用jruby,你可以利用vtd-xml,它具有最高效的内存模型,比DOM效率高3~5倍。

http://vtd-xml.sf.net