ruby - 使用 libxml-ruby 逐 block 处理大型 XML 文件

标签 ruby stream libxml-ruby

我想读一本大书XML包含超过一百万个小型书目记录(如 <article>...</article> )的文件,使用 Ruby 中的 libxml。我已经尝试将 Reader 类与 expand 结合使用一种逐条读取记录的方法,但我不确定这是正确的方法,因为我的代码会占用内存。因此,我正在寻找一个方法,如何以恒定的内存使用量方便地逐个记录地处理记录。下面是我的主循环:

   File.open('dblp.xml') do |io|
      dblp = XML::Reader.io(io, :options => XML::Reader::SUBST_ENTITIES)
      pubFactory = PubFactory.new

      i = 0
      while dblp.read do
        case dblp.name
          when 'article', 'inproceedings', 'book': 
            pub = pubFactory.create(dblp.expand)
            i += 1
            puts pub
            pub = nil
            $stderr.puts i if i % 10000 == 0
            dblp.next
          when 'proceedings','incollection', 'phdthesis', 'mastersthesis':
            # ignore for now
            dblp.next 
          else
            # nothing
        end
      end  
    end

这里的关键是 dblp.expand读取整个子树(如 <article> 记录)并将其作为参数传递给工厂以进行进一步处理。这是正确的方法吗?

然后,在工厂方法中,我使用类似于 XPath 的高级表达式来提取元素的内容,如下所示。同样,这可行吗?

def first(root, node)
    x = root.find(node).first
    x ? x.content : nil
end

pub.pages   = first(node,'pages') # node contains expanded node from dblp.expand

最佳答案

当处理大的 XML 文件时,您应该使用流解析器来避免将所有内容都加载到内存中。有两种常见的方法:

  • 推送解析器,例如 SAX,您可以在其中对遇到的标签使用react(请参阅 tadman 回答)。
  • 拉动解析器,您可以在其中控制 XML 文件中的“光标”,您可以使用简单的原语(例如上移/下移等)移动该光标。

我认为如果你只想检索一些字段,推送解析器很好用,但它们通常用于复杂的数据提取很困惑,并且通常使用 case... when... 构造

在我看来,拉式解析器是基于树的模型和推式解析器之间的一个很好的替代方案。你可以找到一个 nice article在 Dobb 博士关于使用 REXML 拉解析器的日志中。

关于ruby - 使用 libxml-ruby 逐 block 处理大型 XML 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2000118/

相关文章:

ruby-on-rails - Rails 4.0/Linode heisenbugs,部分 deux

ruby - 从 NAnt 调用 rakefile

ruby - 当类从 Hash 继承时,从初始化方法中获取类名

ruby-on-rails - Rails 通知系统

FFMPEG Steam Stream 在几分钟后停止

Node.js:如何通过我的服务器将远程文件流式传输给用户?

windows-xp - Windows XP 上的 libxml-ruby 问题

ruby - 在 heroku : `cannot find Chrome binary` 上使用 chrome 驱动程序运行 selenium

c++ - 如何将内存块的指针转换为标准流