API和XML数据轨道3 Nokogiri

时间:2012-12-13 13:33:01

标签: ruby-on-rails ruby xml nokogiri

这是我第一次尝试从API获取数据,并将数据输出到视图。

我想将ISBN编号放入搜索表单,然后使用http://isbndb.com/获取该特定图书的数据。这就是我到目前为止所做的:

控制器:

require 'open-uri'
class BookController < ApplicationController
  def searchbook
  resp = open("http://isbndb.com/api/books.xml?access_key=#{'API KEY HERE'}&results=texts&index1=isbn&value1=#{params[:isbn]}")
  doc = Nokogiri.XML(resp.read)
  # ... process response here

 end
end

形式:

<%= form_tag({:controller => 'book', :action => 'searchbook'}, {:method => 'get'}) do |select| %>
<%= label_tag :isbn, "Enter ISBN Number" %>
<%= text_field_tag :isbn, params[:isbn] %>
<%= submit_tag "Search" %>
<% end %>

要返回的XML

  <?xml version="1.0" encoding="UTF-8"?>
  <ISBNdb server_time="2005-07-29T03:02:22">
  <BookList total_results="1" page_size="10" page_number="1" shown_results="1">
  <BookData book_id="paul_laurence_dunbar" isbn="0766013502">
  <Title>Paul Laurence Dunbar</Title>
  <TitleLong>Paul Laurence Dunbar: portrait of a poet</TitleLong>
  <AuthorsText>Catherine Reef</AuthorsText>
  <PublisherText publisher_id="enslow_publishers">Berkeley Heights, NJ: Enslow Publishers, c2000.</PublisherText>
  <Summary>A biography of the poet who faced racism and devoted himself to depicting the black experience in America.</Summary>
  <Notes>"Works by Paul Laurence Dunbar": p. 113-114. Includes bibliographical references (p. 124) and index.</Notes>
  <UrlsText></UrlsText>
  <AwardsText></AwardsText>
  </BookData>
</BookList>
  </ISBNdb>

如何处理XML请求或我可以阅读哪些内容以了解如何处理?

在哪里可以查看控制台中返回的数据(如果有)?我甚至不确定这是否正在做任何事情,但是当我点击我的表格中的“搜索”时,我将被带到搜索本行动,这是一个空白页面。

我可能距离整个答案还有很长的路要走,但这是我第一次这样做。

3 个答案:

答案 0 :(得分:1)

我强烈建议您将ISBNdb相关代码移动到自己的模型来简化控制器。一个好方法是通过HTTParty

class ISBNdb
  include HTTParty

  base_uri "http://isbndb.com/api"
  @key = "API_KEY_HERE"

  def self.get_book(isbn)
    params = {'value1' => isbn, 'results' => 'texts', 'index1' => 'isbn', 'access_key' => @key}
    get('/books.xml', :query => params)['ISBNdb']['BookList']['BookData']
  end
end

然后,在您的控制器中,您可以像这样使用它:

book = ISBNdb.get_book('1934356166')
puts book['Title'] #=> "Agile Web Development with Rails"

如您所见,HTTParty为您解析响应,因此您可以像哈希一样访问它。

此解决方案使您的控制器变得简单,并且还为其他API调用添加方法提供了方便的位置,如果您需要其他功能。这是实践中的Single Responsibility Principle

答案 1 :(得分:1)

解析XML很简单:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
  <?xml version="1.0" encoding="UTF-8"?>
  <ISBNdb server_time="2005-07-29T03:02:22">
  <BookList total_results="1" page_size="10" page_number="1" shown_results="1">
  <BookData book_id="paul_laurence_dunbar" isbn="0766013502">
  <Title>Paul Laurence Dunbar</Title>
  <TitleLong>Paul Laurence Dunbar: portrait of a poet</TitleLong>
  <AuthorsText>Catherine Reef</AuthorsText>
  <PublisherText publisher_id="enslow_publishers">Berkeley Heights, NJ: Enslow Publishers, c2000.</PublisherText>
  <Summary>A biography of the poet who faced racism and devoted himself to depicting the black experience in America.</Summary>
  <Notes>"Works by Paul Laurence Dunbar": p. 113-114. Includes bibliographical references (p. 124) and index.</Notes>
  <UrlsText></UrlsText>
  <AwardsText></AwardsText>
  </BookData>
</BookList>
  </ISBNdb>
EOT

isbn_data = doc.search('BookData').map{ |book_data|

  hash = {}

  %w[ book_id isbn ].each do |p|
    hash[p.downcase.to_sym] = book_data[p]
  end

  %w[ Title TitleLong AuthorsText PublisherText Summary ].each do |t|
    hash[t.downcase.to_sym] = book_data.at(t).text
  end

  hash
}

pp isbn_data

哪个输出:

[{:book_id=>"paul_laurence_dunbar",
  :isbn=>"0766013502",
  :title=>"Paul Laurence Dunbar",
  :titlelong=>"Paul Laurence Dunbar: portrait of a poet",
  :authorstext=>"Catherine Reef",
  :publishertext=>"Berkeley Heights, NJ: Enslow Publishers, c2000.",
  :summary=>
   "A biography of the poet who faced racism and devoted himself to depicting the black experience in America."}]

此代码基于您可能正在接收多个<BookData>块的想法,因此它返回一个哈希数组。如果您只使用一次:

hash = {}
book_data = doc.at('BookData')

%w[ book_id isbn ].each do |p|
  hash[p.downcase.to_sym] = book_data[p]
end

%w[ Title TitleLong AuthorsText PublisherText Summary ].each do |t|
  hash[t.downcase.to_sym] = book_data.at(t).text
end

pp hash

输出现在看起来像:

{:book_id=>"paul_laurence_dunbar",
 :isbn=>"0766013502",
 :title=>"Paul Laurence Dunbar",
 :titlelong=>"Paul Laurence Dunbar: portrait of a poet",
 :authorstext=>"Catherine Reef",
 :publishertext=>"Berkeley Heights, NJ: Enslow Publishers, c2000.",
 :summary=>
  "A biography of the poet who faced racism and devoted himself to depicting the black experience in America."}

答案 2 :(得分:0)

当你正在寻找正确方向的基本指向时,我认识到这几点。

1)对于通过HTTP获取任何源,通常使用 HTTP客户端 gem。我可以推荐Excon和被低估的HTTP Client宝石,不过你可以找到更多选项,例如在Ruby工具箱中。

2)要深入了解API响应,您可以例如只是引发输出结果的异常。我从RailsCast学到了这个技术。

# Example with Curb
http = Curl.get("http://www.google.com/")
body = http.body_str

# Raise an exception displaying the value you want to see
raise body.inspect
# or in nicely structured yaml format
raise body.to_yaml

你可以在任何地方使用这种技术,对我来说,当你想要查看你刚刚发送给某个控制器动作的参数时,它会派上用场。

甚至可以通过最近的better_errors gem来获得与返回值进行交互的方法(例如,尝试一些方法调用)。它随附一个控制台,您始终可以通过浏览器与当前环境进行交互。