如何使用单个#each迭代从XML树中提取多个元素

时间:2012-11-14 23:08:41

标签: ruby xml nokogiri

我的xml看起来像这样:

<entry>
  <updated>2012-11-14T13:58:49-07:00</updated>
  <id im:id="557137623" im:bundleId="com.rovio.angrybirdsstarwars">Some text</id>
  <title>Angry Birds Star Wars - Rovio Entertainment Ltd</title>
</entry>
<entry>
  <updated>2012-11-14T13:58:49-07:00</updated>
  <id im:id="557137623" im:bundleId="com.rovio.angrybirdsstarwars">Some text</id>
  <title>Angry Birds Star Wars - Rovio Entertainment Ltd</title>
</entry>

我想用Nokogiri从xml中获取一些数据。即我对上面xml中的im:idim:bundleId<title>感兴趣。

我设法进入了有效的阶段:

xml.css("entry id").each do |entry|
   puts entry["im:id"]
   puts entry["im:bundleid"]
end

问题是要获得title内容,我必须分别迭代xml.css("entry title")。是否有迭代条目然后在同一循环中提取id数据和title

1 个答案:

答案 0 :(得分:6)

首先,您的示例XML未正确嵌套,因此需要修复:

<root>
  <entry>
    <updated>2012-11-14T13:58:49-07:00</updated>
    <id im:id="557137623" im:bundleId="com.rovio.angrybirdsstarwars">Some text</id>
    <title>Angry Birds Star Wars - Rovio Entertainment Ltd</title>
  </entry>
  <entry>
    <updated>2012-11-14T13:58:49-07:00</updated>
    <id im:id="557137623" im:bundleId="com.rovio.angrybirdsstarwars">Some text</id>
    <title>Angry Birds Star Wars - Rovio Entertainment Ltd</title>
  </entry>
</root>

然后,这有效:

require 'nokogiri'
require 'pp'

doc = Nokogiri::XML(<<EOT)
<root>
  <entry>
    <updated>2012-11-14T13:58:49-07:00</updated>
    <id im:id="557137623" im:bundleId="com.rovio.angrybirdsstarwars">Some text</id>
    <title>Angry Birds Star Wars - Rovio Entertainment Ltd</title>
  </entry>
  <entry>
    <updated>2012-11-14T13:58:49-07:00</updated>
    <id im:id="557137623" im:bundleId="com.rovio.angrybirdsstarwars">Some text</id>
    <title>Angry Birds Star Wars - Rovio Entertainment Ltd</title>
  </entry>
</root>
EOT

pp doc.search('entry').map{ |e|
  id = e.at('id')
  [
    id['id'],
    id['bundleId'],
    e.at('title').text
  ]
}

看起来像:

[["557137623",
  "com.rovio.angrybirdsstarwars",
  "Angry Birds Star Wars - Rovio Entertainment Ltd"],
["557137623",
  "com.rovio.angrybirdsstarwars",
  "Angry Birds Star Wars - Rovio Entertainment Ltd"]]

这是有效的,因为我正在浏览entry标签。对于每个entry,我会查找id标记并记住它,以便您可以轻松地针对idbundleID参数重复查看。然后,这是一个简单的案例,可以在e标记内查看title

我确信可以使用一些时髦的XPath来完成,但我很凡人,并希望保持简单。