xpath挑战:如何将多个结果合并为一个结果

时间:2013-03-30 09:43:55

标签: ruby xml xpath nokogiri

我使用Ruby 1.9.3p385并使用Nokogiri来解析XML文件。我不太确定我使用哪个xpath版本,但它确实响应v.1语法/函数,而不是v.2语法。

我有这个XML文件:

<root_tag>
  <middle_tag>
    <item_tag>
      <headline_1>
        <tag_1>Product title 1</tag_1>
      </headline_1>
      <headline_2>
        <tag_2>Product attribute 1</tag_2>
      </headline_2>
    </item_tag>
    <item_tag>
      <headline_1>
        <tag_1>Product title 2</tag_1>
      </headline_1>
      <headline_2>
        <tag_2>Product attribute 2</tag_2>
      </headline_2>
    </item_tag>
  </middle_tag>
</root_tag>

我想提取所有产品,为此我使用此代码:

products = xml_file.xpath("/root_tag/middle_tag/item_tag/headline_1|/root_tag/middle_tag/item_tag/headline_2")

puts products.size # => 4

如果查看输出,请使用:

products.each_with_index do |product, i|
  puts "product #{i}:"
  puts product
end

你明白了:

product 0:
<headline_1>
  <tag_1>Product title 1</tag_1>
</headline_1>
product 1:
<headline_2>
  <tag_2>Product attribute 1</tag_2>
</headline_2>
product 2:
<headline_1>
  <tag_1>Product title 2</tag_1>
</headline_1>
product 3:
<headline_2>
  <tag_2>Product attribute 2</tag_2>
</headline_2>

我需要我的代码将所有匹配加入/合并到相同的结果中(所以products.size应该是2)。最终输出应该如下所示:

product 0:
<headline_1>
  <tag_1>Product title 1</tag_1>
</headline_1>
<headline_2>
  <tag_2>Product attribute 1</tag_2>
</headline_2>
product 1:
<headline_1>
  <tag_1>Product title 2</tag_1>
</headline_1>
<headline_2>
  <tag_2>Product attribute 2</tag_2>
</headline_2>

我看过互联网,但所有变化,例如:

products = xml_file.xpath("/root_tag/middle_tag/item_tag/*[self::headline_1|self::headline_2]")

似乎都输出了相同的结果。

我在xpath中错过了一些重要的观点,还是我忽略了什么?

1 个答案:

答案 0 :(得分:3)

XPath只知道普通序列,因此没有像子序列那样的东西。您必须将每个“产品”包装成一些XML元素。很高兴我们已经有了这样一个元素(<item_tag/>),所以代码很简单:

products = doc.xpath("(//item_tag")
products.each_with_index do |product, i|
  puts "product #{i}:"
  product.children.each do |line|
    puts line
  end
end

输出是(可能需要更多格式化,但我不习惯ruby并且无法帮助你):

product 0:

<headline_1>
        <tag_1>Product title 1</tag_1>
      </headline_1>

<headline_2>
        <tag_2>Product attribute 1</tag_2>
      </headline_2>

product 1:

<headline_1>
        <tag_1>Product title 2</tag_1>
      </headline_1>

<headline_2>
        <tag_2>Product attribute 2</tag_2>
      </headline_2>

要解决所有<headline_n/> - 代码问题,您还可以使用//*[starts-with(local-name(), 'headline')]使代码更加灵活。