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

时间:2011-07-13 06:52:09

标签: ruby xml parsing nokogiri

我正在尝试使用Ruby的Nokogiri来解析大型(1 GB或更多)XML文件。我正在一个较小的文件上测试代码,只包含4个记录available here。我在Ubuntu 10.10上使用Nokogiri版本1.5.0,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或者{{1}}不起作用。

如果有人能够确认我的代码和数据会生成显示的结果并建议我出错的地方,我将不胜感激。

1 个答案:

答案 0 :(得分:19)

流中的每个元素都是两个事件:一个用于打开元素,另一个用于关闭它。开幕活动将有

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

或其他一些变体。