4

我想使用 Ruby 中的 libxml读取一个包含超过一百万个小型书目记录(如)的大型XML文件。<article>...</article>我已经尝试将 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
4

3 回答 3

5

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

  • 像 SAX 这样的推送解析器,当你得到它们时你会对它们做出反应(见tadman答案)。
  • 拉解析器,您可以在其中控制 XML 文件中的“光标”,您可以使用简单的原语(如上/下等)移动它。

我认为如果您只想检索一些字段,推送解析器很适合使用,但它们通常用于复杂的数据提取并且通常使用 usecase... when...构造来实现

在我看来,拉式解析器是基于树的模型和推式解析器之间的一个很好的选择。您可以在 Dobb 博士的期刊中找到一篇关于使用 REXML 的拉式解析器的好文章。

于 2010-01-04T19:28:14.660 回答
1

处理 XML 时,两个常见的选项是基于树的和基于事件的。基于树的方法通常会读入整个 XML 文档,并且会消耗大量内存。基于事件的方法不使用额外的内存,但除非您编写自己的处理程序逻辑,否则不会做任何事情。

SAX 风格的解析器和衍生实现采用基于事件的模型。

REXML 示例:http ://www.iro.umontreal.ca/~lapalme/ForestInsteadOfTheTrees/HTML/ch08s01.html

REXML:http ://ruby-doc.org/stdlib/libdoc/rexml/rdoc/index.html

于 2010-01-04T15:19:47.390 回答
0

我有同样的问题,但我想我通过调用 Node#remove 解决了它!在展开的节点上。在你的情况下,我认为你应该做类似的事情

my_node = dblp.expand
[用 my_node 做你必须做的事]
dblp.next
my_node.remove!

不太确定为什么会这样,但是如果您查看 LibXML::XML::Reader#expand 的源代码,就会看到有关释放节点的评论。我猜 Reader#expand 将节点与 Reader 相关联,您必须调用 Node#remove!释放它。

即使有这个 hack,内存使用也不是很好,但至少它没有继续增长。

于 2010-02-11T13:36:27.240 回答