【问题标题】:Parse XML with NokogiriParse XML with Nokogiri
【发布时间】:2012-12-15 22:36:56
【问题描述】:

在正确设置 Nokogiri 和他们的文档时遇到一些问题,入门有点粗糙。

我正在尝试解析 XML 文件:http://www.kongregate.com/games_for_your_site.xml

它返回游戏集中的多个游戏,每个游戏都有一个标题、描述等......

<gameset>
  <game>
    <id>160342</id>
    <title>Tricky Rick</title>
    <thumbnail>
      http://cdn3.kongregate.com/game_icons/0042/7180/KONG_icon250x200_site.png?21656-op
    </thumbnail>
    <launch_date>2012-12-12</launch_date>
    <category>Puzzle</category>
    <flash_file>
      http://external.kongregate-games.com/gamez/0016/0342/live/embeddable_160342.swf
    </flash_file>
    <width>640</width>
    <height>480</height>
    <url>
      http://www.kongregate.com/games/tAMAS_Games/tricky-rick
    </url>
    <description>
      Help Rick to collect all the stolen fuel to refuel his spaceship and fly away from the planet. Use hammer, bombs, jetpack and other useful stuff to solve puzzles!
    </description>
    <instructions>
      WASD \ Arrow Keys &#8211; move; S \ Down Arrow &#8211; take\release an object; CNTRL &#8211; interaction with objects: throw, hammer strike, invisibility mode; SPACE &#8211; interaction with elevators and fuel stations; Esc \ P &#8211; pause;
    </instructions>
    <developer_name>tAMAS_Games</developer_name>
    <gameplays>24999</gameplays>
    <rating>3.43</rating>
  </game>
  <game>
    <id>160758</id>
    <title>Flying Cookie Quest</title>
    <thumbnail>
      http://cdn2.kongregate.com/game_icons/0042/8428/icon_cookiequest_kong_250x200_site.png?16578-op
    </thumbnail>
    <launch_date>2012-12-07</launch_date>
    <category>Action</category>
    <flash_file>
      http://external.kongregate-games.com/gamez/0016/0758/live/embeddable_160758.swf
    </flash_file>
    <width>640</width>
    <height>480</height>
    <url>
      http://www.kongregate.com/games/LongAnimals/flying-cookie-quest
    </url>
    <description>
      Launch Rocket Panda into the land of Cookies. With the help of low-flying sharks, hang-gliding sheep and Rocket Badger, can you defeat the all powerful Biscuit Head? Defeat All enemies of cookies in this launcher game.
    </description>
    <instructions>Use the mouse button!</instructions>
    <developer_name>LongAnimals</developer_name>
    <gameplays>168672</gameplays>
    <rating>3.67</rating>
  </game>

从文档中,我使用的是:

require 'nokogiri'
require 'open-uri'

url = "http://www.kongregate.com/games_for_your_site.xml"
xml = Nokogiri::XML(open(url))
xml.xpath("//game").each do |node|
    puts node.xpath("//id")
    puts node.xpath("//title")
    puts node.xpath("//thumbnail")
    puts node.xpath("//category")
    puts node.xpath("//flash_file")
    puts node.xpath("//width")
    puts node.xpath("//height")
    puts node.xpath("//description")
    puts node.xpath("//instructions")
end

但是,它只是返回无穷无尽的数据,而不是在一个集合中。任何帮助都会有所帮助。

【问题讨论】:

  • 您认为 Nokogiri 文档“粗糙”的原因是什么? nokogiri.org 的教程是否缺少一些东西? rdoc 文档是否缺少对您有帮助的内容?
  • 这确实与下面锡人所说的有关

标签: ruby-on-rails ruby xml-parsing nokogiri


【解决方案1】:

我会这样重写你的代码:

xml = Nokogiri::XML(open("http://www.kongregate.com/games_for_your_site.xml"))
xml.xpath("//game").each do |game|
  %w[id title thumbnail category flash_file width height description instructions].each do |n|
    puts game.at(n)
  end
end

代码中的问题是所有子标签都以// 为前缀,在XPath 中,这意味着“从根节点开始向下搜索包含该文本的所有标签”。因此,它不是只在每个 //game 节点内搜索,而是在整个文档中搜索每个 //game 节点的每个列出的标签。

我建议在 XPath 上使用 CSS 访问器,因为它们更简单(通常)并且因此更易于阅读。因此,我使用search('game') 而不是xpath('//game')。 (search 将采用 CSS 或 XPath 访问器,at 也将采用。)

如果您想要标签中包含的文本,请将puts game.at(n) 更改为:

puts game.at(n).text

为了使输出更有用,我会这样做:

require 'nokogiri'
require 'open-uri'

xml = Nokogiri::XML(open('http://www.kongregate.com/games_for_your_site.xml'))
games = xml.search('game').map do |game|
  %w[
    id title thumbnail category flash_file width height description instructions
  ].each_with_object({}) do |n, o|
    o[n] = game.at(n).text
  end
end

require 'awesome_print'
puts games.size
ap games.first
ap games.last

结果:

395
{
              "id" => "160342",
          "title"  => "Tricky Rick",
      "thumbnail"  => "http://cdn3.kongregate.com/game_icons/0042/7180/KONG_icon250x200_site.png?21656-op",
        "category" => "Puzzle",
      "flash_file" => "http://external.kongregate-games.com/gamez/0016/0342/live/embeddable_160342.swf",
          "width"  => "640",
          "height" => "480",
    "description"  => "Help Rick to collect all the stolen fuel to refuel his spaceship and fly away from the planet. Use hammer, bombs, jetpack and other useful stuff to solve puzzles!\n",
    "instructions" => "WASD \\ Arrow Keys &#8211; move;\nS \\ Down Arrow &#8211; take\\release an object;\nCNTRL &#8211; interaction with objects: throw, hammer strike, invisibility mode;\nSPACE &#8211; interaction with elevators and fuel stations;\nEsc \\ P &#8211; pause;\n"
}
{
              "id" => "78",
          "title"  => "rotaZion",
      "thumbnail"  => "http://cdn2.kongregate.com/game_icons/0000/0115/pixtiz.rotazion_icon.jpg?8217-op",
        "category" => "Action",
      "flash_file" => "http://external.kongregate-games.com/gamez/0000/0078/live/embeddable_78.swf",
          "width"  => "350",
          "height" => "350",
    "description"  => "In rotaZion, you play with a bubble bar that you can&#8217;t stop rotating !\nCollect the bubbles and try to avoid the mines !\nCollect the different bonus to protect your bubble bar, makes the mines go slower or destroy all the mines !\nTry to beat 100.000 points ;)\n",
    "instructions" => "Move the bubble bar with the arrow keys !\nBubble = 500 Points !\nPixtiz sign = 5000 Points !\n"
}

【讨论】:

  • 优秀的答案。 +1 所有解释以及代码。
  • XPath // 在每个人开始使用它时都会欺骗他们。
  • 这很好,但最终目标是将其存储到数据库中,游戏集中的每个游戏对应一行。这可以发生在这个数组之外吗?
  • 很容易。我们一直都在这样做,但是如何让您弄清楚。一个提示是每个嵌入的哈希都是一个单独的行。如果键不直接映射到字段名称,您可以使用适当的字段名称和zip 创建一个数组,其中每个哈希的values,然后使用Hash[['foo','bar'].zip(hash.values)] 之类的东西将其转换为哈希。此外,一些 DBM 可以直接导入 XML,因此可能不需要解析它。导入临时表,删除不需要的字段,然后将生成的表复制到生产表中。
【解决方案2】:

你可以试试这样的。我建议为您想要的游戏内部元素创建一个数组,然后对其进行迭代。我确信有一种方法可以在 Nokogiri 中获取指定元素中的所有元素,但这很有效:

   xml = Nokogiri::XML(result)
    xml.css("game").each do |inv|
      inv.css("title").each do |f|  # title or whatever else you want
        puts f.inner_html
      end
    end

【讨论】:

  • inner_html 很少有用。在这种情况下,您确实需要 f.text,并且由于每个游戏只有一个标题,因此不需要 each
猜你喜欢
  • 2017-07-13
  • 2012-07-16
  • 2013-07-10
  • 1970-01-01
  • 2012-09-21
  • 1970-01-01
  • 2010-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多