Rails使用Nokogiri解析大型XML :: XML :: Reader => Model.create

时间:2012-09-19 10:20:46

标签: ruby-on-rails xml nokogiri

我有很多大型(32 Mb)XML文件,其中包含来自不同商店的产品信息。我正在使用在Heroku上托管的Rails。

我想解析这些XML-feeds并将这些产品写入我的数据库。我有一个半工作的解决方案,但它非常慢,而且内存密集。

到目前为止,我已经或多或少地使用了这个:

open_uri_fetched = open(xml_from_url)
xml_list = Nokogiri::HTML(open_uri_fetched)
xml_list.xpath("//product").each do |product|
// parsed nodes
// Model.create()
end

这在某种程度上起了作用。但是,这导致Heroku上的内存问题导致脚本崩溃。它也非常慢(我为200多个Feed提供此功能)。

Heroku告诉我使用Nokogiri :: XML :: Reader来解决这个问题,这就是我现在要做的事情。

我也研究过使用:

ActiveRecord::Base.transaction do
Model.create()
end

加速Model.create() - 进程。

1。我的第一个问题:这是解决我问题的正确方法(或至少是一种体面的方式)吗?

现在,这就是我尝试做的事情:

  reader = Nokogiri::XML::Reader(File.open('this_feed.xml'))
  reader.each do |node|
    if node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
      if node.name.downcase == xname
        puts "Name: " + node.inner_xml
        use_name = node.inner_xml
      end
    end
  end

问题2:但我在哪里放置模型创建代码?

ActiveRecord::Base.transaction do
  Model.create(:name => use_name)
end

如果我把它放在循环中,它将尝试为每个节点创建,这是错误的。我希望在xml-list中的每个产品之后调用它,对吗?

如果我创建一个在读取XML期间构建的Hash(然后用于创建模型创建),那么这不会像打开XML文件那样占用内存吗?

简而言之,XML文件看起来像这样:

<?xml version="1.0" encoding="UTF-8" ?>
<products>
    <product>
        <name>This cool product</name>
        <categories>
            <category>Food</category>
            <category>Drinks</category>
        </categories>
        <SKU />
        <EAN />
        <description>A long description...</description>
        <model />
        <brand />
        <gender />
        <price>126.00</price>
        <regularPrice>126.00</regularPrice>
        <shippingPrice />
        <currency>SEK</currency>
        <productUrl>http://www.domain.com/1.html</productUrl>
        <graphicUrl>http://www.domain.com/1.jpg</graphicUrl>
        <inStock />
        <inStockQty />
        <deliveryTime />
    </product>
</products>

1 个答案:

答案 0 :(得分:3)

Reader只需一次扫描文档。你必须自己跟踪状态:你看过哪些元素,你是否在你关心的元素内等等。

This gist是一个鲜为人知的美女,大大改善了读者的语法。它以一种非常容易阅读的方式为您跟踪状态。

以下是一个如何使用它的示例,取自评论:

Xml::Parser.new(Nokogiri::XML::Reader(open(file))) do
  inside_element 'User' do
    for_element 'Name' do puts "Username: #{inner_xml}" end
    for_element 'Email' do puts "Email: #{inner_xml}" end

    for_element 'Address' do
      puts 'Start of address:'
      inside_element do
        for_element 'Street' do puts "Street: #{inner_xml}" end
        for_element 'Zipcode' do puts "Zipcode: #{inner_xml}" end
        for_element 'City' do puts "City: #{inner_xml}" end
      end
      puts 'End of address'
    end
  end
end

有人应该用这个小宝石制作宝石。

在您的情况下,您可以拥有inside_element 'product'块,提取所需的元素,并在产品块的末尾创建模型实例。