我该如何使用Nokogiri::XML::Reader解析大型XML文件?

13

我正在尝试使用Ruby的Nokogiri解析大型(1 GB或更大)的XML文件。我正在一个仅包含4个记录的较小文件上测试代码(可在此处获取)。我使用的是Nokogiri 1.5.0版本、Ubuntu 10.10上的Ruby 1.8.7。由于我不太理解SAX,所以我尝试使用Nokogiri::XML::Reader开始。

我的第一次尝试,是想要检索PMID标签的内容,代码如下:

#!/usr/bin/ruby
require "rubygems"
require "nokogiri"

file   = ARGV[0]
reader = Nokogiri::XML::Reader(File.open(file))
p      = []
reader.each do |node|
  if node.name == "PMID"
    p << node.inner_xml
  end
end

puts p.inspect

这是我希望看到的内容:

["21714156", "21693734", "21692271", "21692260"]

这是我实际看到的内容:

["21714156", "", "21693734", "", "21692271", "", "21692260", ""]

看起来由于某些原因,我的代码对于每个PMID实例都会发现或生成一个额外的、空的PMID标签。要么是inner_xml不像我想象的那样正常工作了。

如果有人能确认我的代码和数据是否生成了所示结果,并建议我在哪里出错,我将不胜感激。


在“旧时代”,在我们拥有许多GB的RAM主机之前,我们曾经担心加载一两个GB的内容。现在,除非存在接收意外文件会消耗所有可用RAM的风险,否则我会尝试让Nokogiri和Ruby拉取完整大小的文件。是的,1GB是很多文本,但在8GB或16GB系统上,它什么都不是。观察加载和处理时间是否改善或受到影响,因为内存分配和垃圾回收可能会影响速度;在这种情况下使用SAX模型可以帮助,但我更喜欢将其加载并像DOM一样处理。 - the Tin Man
速度比RAM更重要。例如,我在一台拥有96 GB RAM的共享服务器上尝试使用Hpricot(我的首选库)进行解析:需要72分钟。 - neilfws
我已经有几年没有关注Hpricot了;我曾经经常使用它,但遇到了一些问题,它总是以壮观的方式崩溃,而Nokogiri则没有这个问题,所以我转换了工具并且一直沿用至今。72分钟似乎是一个很长的运行时间。您可以尝试运行分析器,看看是否能揭示出任何问题。否则,请总结代码和XML,并在此处发布,我们将尝试帮助加快速度。 - the Tin Man
1个回答

21

流式数据中的每个元素都会作为两个事件传输:一个用于打开元素,一个用于关闭元素。打开元素事件将具有

node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT

并且结束事件将会拥有

node.node_type == Nokogiri::XML::Reader::TYPE_END_ELEMENT

你看到的空字符串只是元素关闭事件。要记住,在SAX解析中,你基本上是遍历一棵树,所以需要第二个事件告诉你何时返回并关闭一个元素。

你可能想要类似这样的代码:

reader.each do |node|
  if node.name == "PMID" && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
    p << node.inner_xml
  end
end

或者也许:

reader.each do |node|
  next if node.name      != 'PMID'
  next if node.node_type != Nokogiri::XML::Reader::TYPE_ELEMENT
  p << node.inner_xml
end

或者使用其他变体。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接