我有很多大型(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>
答案 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'
块,提取所需的元素,并在产品块的末尾创建模型实例。