我有一个类似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
在这个地方使用nokogiri似乎有点过大。您可以使用普通ruby:
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)
那么您就可以访问作为散列对象的数据。
如果我们缩进你的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>
And try again…
如果不能更改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
只需改变一行:
doc.css("CATEGORY").each do |node|
到下面:
doc.css("CATEGORY:has(CATEGORY_FULLNAME)").each do |node|
只选择包含CATEGORY_FULLNAME
子元素的CATEGORY
元素
doc.xpath("//CATEGORY[CATEGORY_FULLNAME]").each do |node|