Rails 4将XML解析为表

时间:2014-05-21 10:05:25

标签: ruby-on-rails ruby xml nokogiri

我有像http://www.heureka.cz/direct/xml-export/shops/heureka-sekce.xml这样的XML文件。我无法改变它,因为它不是我的。它只是从另一个网站解析。

这是XML(带结构):

<HEUREKA>
  <CATEGORY>
    <CATEGORY_ID>971</CATEGORY_ID>
    <CATEGORY_NAME>Auto-moto</CATEGORY_NAME>
    <CATEGORY>
      <CATEGORY_ID>881</CATEGORY_ID>
      <CATEGORY_NAME>Alkohol testery</CATEGORY_NAME>
      <CATEGORY_FULLNAME>Heureka.cz | Auto-moto | Alkohol testery</CATEGORY_FULLNAME>
    </CATEGORY>
  </CATEGORY>
</HEUREKA>

感谢所有评论,这是最终的代码

def heureka
require 'open-uri'
require 'nokogiri'
doc = Nokogiri::XML(open("http://www.heureka.cz/direct/xml-export/shops/heureka-sekce.xml"))

doc.xpath("//CATEGORY[CATEGORY_FULLNAME]").each do |node|
record = Heureka.where("name" => node.css('CATEGORY_NAME').inner_text).first_or_initialize
record.fullname=node.xpath('CATEGORY_FULLNAME').inner_text
record.name=node.xpath('CATEGORY_NAME').inner_text                                                                                         
record.save unless record.fullname.blank?                                                                                                  
end                                                                                                                                        
end                         

3 个答案:

答案 0 :(得分:5)

在这个地方使用nokogiri似乎有点过分。你可以用普通红宝石做到这一点:

require 'net/http'
xml_content = Net::HTTP.get(URI.parse('http://www.heureka.cz/direct/xml-export/shops/heureka-sekce.xml'))
data = Hash.from_xml(xml_content)

然后您可以作为哈希对象访问数据。

答案 1 :(得分:1)

如果我们缩进您的XML,您将看到问题:

<HEUREKA>
  <CATEGORY>
    <CATEGORY_ID>971</CATEGORY_ID>
    <CATEGORY_NAME>Auto-moto</CATEGORY_NAME>
    <CATEGORY>
      <CATEGORY_ID>881</CATEGORY_ID>
      <CATEGORY_NAME>Alkohol testery</CATEGORY_NAME>
      <CATEGORY_FULLNAME>Heureka.cz | Auto-moto | Alkohol testery</CATEGORY_FULLNAME>
    </CATEGORY>
  </CATEGORY>
</HEUREKA>

第二个类别节点是里面第一个类别节点,所以它也是它的子节点。因为children.css('CATEGORY_NAME').inner_text将返回第一个节点连接的两个名称(Auto-motoAlkohol testery),最后一个将具有预期的数据 - (Alkohol testery)。

修复您的XML:

<HEUREKA>
  <CATEGORY>
    <CATEGORY_ID>971</CATEGORY_ID>
    <CATEGORY_NAME>Auto-moto</CATEGORY_NAME>
  </CATEGORY>
  <CATEGORY>
    <CATEGORY_ID>881</CATEGORY_ID>
    <CATEGORY_NAME>Alkohol testery</CATEGORY_NAME>
    <CATEGORY_FULLNAME>Heureka.cz | Auto-moto | Alkohol testery</CATEGORY_FULLNAME>
  </CATEGORY>
</HEUREKA>

再试一次......


<强>更新

如果您无法更改XML,则可以使用XPATH代替CSS,因为其默认行为是找到直接子项,而不是所有的孩子(深儿):

def heurekacat
  require 'open-uri'
  require 'nokogiri'
  doc = Nokogiri::XML(open("http://www.heureka.cz/direct/xml-export/shops/heureka-sekce.xml"))
  doc.css("CATEGORY").each do |node|
    record = HeurekaCat.where("name" => children.xpath('CATEGORY_NAME').inner_text).first_or_initialize
    record.category=node.xpath('CATEGORY_FULLNAME').inner_text
    record.name=node.xpath('CATEGORY_NAME').inner_text
    record.save
  end
end

答案 2 :(得分:0)

只需更改一行:

doc.css("CATEGORY").each do |node|

以下内容:

doc.css("CATEGORY:has(CATEGORY_FULLNAME)").each do |node|

这仅选择包含CATEGORY子元素的CATEGORY_FULLNAME个元素。

作为替代方案,等效的XPath:

doc.xpath("//CATEGORY[CATEGORY_FULLNAME]").each do |node|