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

2024-03-25

我想读一本大书XML http://dblp.uni-trier.de/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>record)并将其作为参数传递给工厂进行进一步处理。这是正确的方法吗?

然后,在工厂方法中,我使用类似 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 一样,当你遇到标签时你会做出反应(参见tadman回答)。
  • 拉解析器,您可以在 XML 文件中控制“光标”,可以使用简单的原语(例如向上/向下等)移动该“光标”。

我认为如果您只想检索某些字段,则推送解析器很好用,但它们通常用于复杂的数据提取很混乱,并且通常使用以下方式实现case... when...结构体

在我看来,拉式解析器是基于树的模型和推式解析器之间的一个很好的替代方案。你可以找到一个好文章 http://www.ddj.com/web-development/184406385在 Dobb 博士的期刊中,有关使用 REXML 进行拉解析器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 libxml-ruby 逐块处理大型 XML 文件 的相关文章

随机推荐