เมษายน 2008
- บทนำ
- การขอรับและติดตั้ง Ruby
- การตรวจสอบสิทธิ์ | การใช้ Spreadsheets API
- การขอรับเวิร์กชีต
- การโพสต์เนื้อหาไปยัง ListFeed
- การใช้ cellsFeed เพื่ออัปเดตเนื้อหา
- สรุป
บทนำ
Ruby เป็นภาษาการเขียนสคริปต์แบบไดนามิกที่ได้รับความสนใจเป็นอย่างมากในช่วงไม่กี่ปีที่ผ่านมา เนื่องจากเฟรมเวิร์กการพัฒนาเว็บ Rails ที่ได้รับความนิยม บทความนี้จะอธิบายวิธีใช้ Ruby เพื่อโต้ตอบกับบริการ Google Data API เราจะไม่เน้นที่ Rails แต่จะสนใจอธิบายคำสั่ง HTTP พื้นฐานและโครงสร้างของฟีดมากกว่า คุณทำตามตัวอย่างทั้งหมดที่แสดงที่นี่ได้จากบรรทัดคำสั่งโดยใช้ irb ซึ่งเป็นเชลล์แบบอินเทอร์แอกทีฟของ Ruby
ดังที่คุณอาจจำได้จากบทความ cURL, Google Data API ใช้ Atom Publishing Protocol เพื่อแสดง สร้าง และอัปเดตทรัพยากรบนเว็บ ข้อดีของโปรโตคอลนี้คือใช้คำกริยา HTTP มาตรฐานในการสร้างคำขอ ซึ่งจะตอบกลับด้วยรหัสสถานะ HTTP มาตรฐาน
คำกริยาที่เราจะใช้ในบทความนี้คือ GET เพื่อดึงข้อมูลเนื้อหา POST เพื่ออัปโหลดเนื้อหาใหม่ และ PUT เพื่ออัปเดตเนื้อหาที่มีอยู่ รหัสมาตรฐานบางอย่างที่คุณอาจพบเมื่อใช้ Google Data API คือ 200 ซึ่งแสดงถึงการดึงข้อมูลฟีดหรือรายการสำเร็จ หรือ 201 ซึ่งแสดงถึงการสร้างหรืออัปเดตทรัพยากรสำเร็จ หากเกิดข้อผิดพลาด เช่น เมื่อมีการส่งคำขอที่มีรูปแบบไม่ถูกต้อง ระบบจะส่งรหัส 400 (หมายถึง "คำขอไม่ถูกต้อง") กลับไป ข้อความที่ละเอียดมากขึ้นจะอยู่ในเนื้อหาการตอบกลับ ซึ่งจะอธิบายว่าเกิดข้อผิดพลาดใดขึ้น
Ruby มีตัวเลือกการแก้ไขข้อบกพร่องที่ยอดเยี่ยมเป็นส่วนหนึ่งของโมดูล "Net" เพื่อไม่ให้ตัวอย่างโค้ดเหล่านี้ยาวเกินไป ฉันจึงไม่ได้เปิดใช้ที่นี่
การขอรับและติดตั้ง Ruby
คุณติดตั้ง Ruby ได้โดยใช้ระบบการจัดการแพ็กเกจส่วนใหญ่หากใช้ Linux สำหรับระบบปฏิบัติการอื่นๆ และหากต้องการรับซอร์สโค้ดทั้งหมด โปรดไปที่ http://www.ruby-lang.org/en/downloads/ Irb ซึ่งเป็นเชลล์แบบอินเทอร์แอกทีฟที่เราจะใช้สำหรับตัวอย่างเหล่านี้ควรได้รับการติดตั้งโดยค่าเริ่มต้น หากต้องการทำตามตัวอย่างโค้ดที่แสดงที่นี่ คุณจะต้องติดตั้ง XmlSimple
ซึ่งเป็นไลบรารีขนาดเล็กสำหรับแยกวิเคราะห์ XML เป็นโครงสร้างข้อมูล Ruby หากต้องการรับ/ติดตั้ง XmlSimple โปรดไปที่ http://xml-simple.rubyforge.org/
เมื่อมีสำเนาของ Ruby ที่ทำงานในเครื่องแล้ว คุณจะใช้แพ็กเกจ Net:HTTP
เพื่อส่งคำขอพื้นฐานไปยังบริการข้อมูลของ Google ได้ ข้อมูลโค้ดด้านล่างแสดงวิธีนำเข้าที่จำเป็นจากเชลล์แบบอินเทอร์แอกทีฟของ Ruby สิ่งที่เราทำคือการกำหนดให้ใช้แพ็กเกจ "net/http" แยกวิเคราะห์ URL สำหรับฟีดวิดีโอที่ได้รับคะแนนสูงสุดจาก YouTube แล้วส่งคำขอ HTTP GET
irb(main):001:0> require 'net/http' => true irb(main):002:0> youtube_top_rated_videos_feed_uri = \ 'http://gdata.youtube.com/feeds/api/standardfeeds/top_rated' => "http://gdata.youtube.com/feeds/api/standardfeeds/top_rated" irb(main):003:0> uri = \ URI.parse(youtube_top_rated_videos_feed_uri) => #<URI::HTTP:0xfbf826e4 URL:http://gdata.youtube.com/feeds/api/standardfeeds/top_rated> irb(main):004:0> uri.host => "gdata.youtube.com" irb(main):005:0> Net::HTTP.start(uri.host, uri.port) do |http| irb(main):006:1* puts http.get(uri.path) irb(main):007:1> end #<Net::HTTPOK:0xf7ef22cc>
คำขอดังกล่าวควรแสดง XML จำนวนมากในบรรทัดคำสั่ง คุณอาจสังเกตเห็นว่ารายการทั้งหมดอยู่ในองค์ประกอบ <feed> และเรียกว่าองค์ประกอบ <entry> เรายังไม่ต้องกังวลเรื่องการจัดรูปแบบ XML ในตอนนี้ เพียงแค่อยากอธิบายวิธีสร้างคำขอ Google Data API พื้นฐานโดยใช้ HTTP ตอนนี้เราจะเปลี่ยนไปใช้ API อื่นและมุ่งเน้นที่สเปรดชีต เนื่องจากข้อมูลที่เราส่งและดึงข้อมูลได้นั้น "เป็นมิตรกับบรรทัดคำสั่ง" มากกว่า
การตรวจสอบสิทธิ์ | การใช้ Google Spreadsheets API
เราจะเริ่มต้นด้วยการดึงข้อมูลฟีดขององค์ประกอบรายการอีกครั้ง แต่คราวนี้เราจะใช้สเปรดชีตของเราเอง หากต้องการดำเนินการดังกล่าว เราต้องตรวจสอบสิทธิ์กับบริการบัญชี Google ก่อน
ดังที่คุณอาจทราบจากเอกสารประกอบเกี่ยวกับการตรวจสอบสิทธิ์ GData การตรวจสอบสิทธิ์กับบริการของ Google ทำได้ 2 วิธี AuthSub ใช้สำหรับแอปพลิเคชันบนเว็บและเกี่ยวข้องกับกระบวนการแลกเปลี่ยนโทเค็นโดยย่อ ประโยชน์ที่แท้จริงของ AuthSub คือแอปพลิเคชันของคุณไม่จำเป็นต้องจัดเก็บข้อมูลเข้าสู่ระบบของผู้ใช้ ClientLogin ใช้สำหรับแอปพลิเคชันที่ "ติดตั้ง" ในกระบวนการ ClientLogin ระบบจะส่งชื่อผู้ใช้และรหัสผ่านไปยังบริการของ Google ผ่าน https พร้อมกับสตริงที่ระบุบริการที่คุณต้องการใช้ บริการ Google Spreadsheets API จะระบุด้วยสตริง wise
กลับไปที่เชลล์แบบอินเทอร์แอกทีฟของเรา แล้วมาตรวจสอบสิทธิ์ด้วย Google กัน โปรดทราบว่าเราใช้ https เพื่อส่งคำขอการตรวจสอบสิทธิ์และข้อมูลเข้าสู่ระบบ
irb(main):008:0> require 'net/https' => true irb(main):009:0> http = Net::HTTP.new('www.google.com', 443) => #<Net::HTTP www.google.com:443 open=false> irb(main):010:0> http.use_ssl = true => true irb(main):011:0> path = '/accounts/ClientLogin' => "/accounts/ClientLogin" # Now we are passing in our actual authentication data. # Please visit OAuth For Installed Apps for more information # about the accountType parameter irb(main):014:0> data = \ irb(main):015:0* 'accountType=HOSTED_OR_GOOGLE&Email=your email' \ irb(main):016:0* '&Passwd=your password' \ irb(main):017:0* '&service=wise' => accountType=HOSTED_OR_GOOGLE&Email=your email&Passwd=your password&service=wise" # Set up a hash for the headers irb(main):018:0> headers = \ irb(main):019:0* { 'Content-Type' => 'application/x-www-form-urlencoded'} => {"Content-Type"=>"application/x-www-form-urlencoded"} # Post the request and print out the response to retrieve our authentication token irb(main):020:0> resp, data = http.post(path, data, headers) warning: peer certificate won't be verified in this SSL session => [#<Net::HTTPOK 200 OK readbody=true>, "SID=DQAAAIIAAADgV7j4F-QVQjnxdDRjpslHKC3M ... [ snipping out the rest of the authentication strings ] # Strip out our actual token (Auth) and store it irb(main):021:0> cl_string = data[/Auth=(.*)/, 1] => "DQAAAIUAAADzL... [ snip ] # Build our headers hash and add the authorization token irb(main):022:0> headers["Authorization"] = "GoogleLogin auth=#{cl_string}" => "GoogleLogin auth=DQAAAIUAAADzL... [ snip ]
โอเค ตอนนี้เราได้รับการตรวจสอบสิทธิ์แล้ว มาลองดึงข้อมูลสเปรดชีตของเราเองโดยใช้คำขอไปยัง
http://spreadsheets.google.com/feeds/spreadsheets/private/full
เนื่องจากนี่คือคำขอที่ได้รับการตรวจสอบสิทธิ์ เราจึงต้องการส่งในส่วนหัวด้วย ในความเป็นจริง เนื่องจากเราจะส่งคำขอหลายรายการสำหรับฟีดต่างๆ เราจึงควรห่อหุ้มฟังก์ชันนี้ไว้ในฟังก์ชันง่ายๆ ซึ่งเราจะเรียกว่า get_feed
# Store the URI to the feed since we may want to use it again
irb(main):023:0> spreadsheets_uri = \
irb(main):024:0* 'http://spreadsheets.google.com/feeds/spreadsheets/private/full'
# Create a simple method to obtain a feed
irb(main):025:0> def get_feed(uri, headers=nil)
irb(main):026:1> uri = URI.parse(uri)
irb(main):027:1> Net::HTTP.start(uri.host, uri.port) do |http|
irb(main):028:2* return http.get(uri.path, headers)
irb(main):029:2> end
irb(main):030:1> end
=> nil
# Lets make a request and store the response in 'my_spreadsheets'
irb(main):031:0> my_spreadsheets = get_feed(spreadsheets_uri, headers)
=> #<Net::HTTPOK 200 OK readbody=true>
irb(main):032:0> my_spreadsheets
=> #<Net::HTTPOK 200 OK readbody=true>
# Examine our XML (showing only an excerpt here...)
irb(main):033:0> my_spreadsheets.body
=> "<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'>
<id>http://spreadsheets.google.com/feeds/spreadsheets/private/full</id><updated>2008-03-20T20:49:39.211Z</updated>
<category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#spreadsheet'/>
<title type='text'>Available Spreadsheets - test.api.jhartmann@gmail.com</title><link rel='alternate' type='text/html' href='http://docs.google.com'/>
<link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/spreadsheets/private/full'/><link rel='self' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/spreadsheets/private/full?tfe='/>
<openSearch:totalResults>6</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><entry>
<id>http://spreadsheets.google.com/feeds/spreadsheets/private/full/o04927555739056712307.4365563854844943790</id><updated>2008-03-19T20:44:41.055Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#spreadsheet'/><title type='text'>test02</title><content type='text'>test02</content><link rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/worksheets/o04927555739056712307.4365563854844943790/private/full'/><link rel='alternate' type='text/html' href='http://spreadsheets.google.com/ccc?key=o04927555739056712307.4365563854844943790'/><link rel='self' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/spreadsheets/private/full/o04927555739056712307.4365563854844943790'/><author><name>test.api.jhartmann</name><email>test.api.jhartmann@gmail.com</email></author></entry><entry> ...
อีกครั้งที่เราเห็น XML จำนวนมากซึ่งเราได้ลดความสำคัญลงแล้วข้างต้นเนื่องจากคุณไม่จำเป็นต้องกังวลเกี่ยวกับการถอดรหัสจากบรรทัดคำสั่ง เพื่อให้อ่านง่ายขึ้น เราจะแยกวิเคราะห์เป็นโครงสร้างข้อมูลโดยใช้ XmlSimple
แทน
# Perform imports irb(main):034:0> require 'rubygems' => true irb(main):035:0> require 'xmlsimple' => true irb(main):036:0> doc = \ irb(main):037:0* XmlSimple.xml_in(my_spreadsheets.body, 'KeyAttr' => 'name') # Import the 'pp' module for 'pretty printing' irb(main):038:0> require 'pp' => true # 'Pretty-print' our XML document irb(main):039:0> pp doc {"totalResults"=>["6"], "category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#spreadsheet", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "title"=> [{"type"=>"text", "content"=>"Available Spreadsheets - Test-account"}], "startIndex"=>["1"], "id"=>["http://spreadsheets.google.com/feeds/spreadsheets/private/full"], "entry"=> [{"category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#spreadsheet", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "title"=>[{"type"=>"text", "content"=>"blank"}], "author"=> [{"name"=>["Test-account"], "email"=>["my email"]}], "id"=> ["http://spreadsheets.google.com/feeds/spreadsheets/private/full/o04927555739056712307.3387874275736238738"], "content"=>{"type"=>"text", "content"=>"blank"}, "link"=> [ snipping out the rest of the XML ]
การขอรับเวิร์กชีต
ดังนั้นตามที่เห็นในเอาต์พุตด้านบน ฟีดของฉันมีสเปรดชีต 6 รายการ เพื่อไม่ให้บทความนี้ยาวเกินไป ฉันจึงตัดเอาต์พุต XML ที่เหลือออกไป (รวมถึงในข้อมูลอื่นๆ ส่วนใหญ่ด้วย) หากต้องการเจาะลึกสเปรดชีตนี้ เราจะต้องทำตามขั้นตอนเพิ่มเติมอีก 2-3 ขั้นตอน
- รับคีย์สเปรดชีต
- ใช้คีย์สเปรดชีตเพื่อรับฟีดเวิร์กชีต
- รับรหัสของเวิร์กชีตที่เราต้องการใช้
- ขอ cellsFeed หรือ listFeed เพื่อเข้าถึงเนื้อหาจริงของสเปรดชีต
แม้ว่าอาจฟังดูเหมือนงานหนัก แต่ฉันจะแสดงให้เห็นว่าทุกอย่างค่อนข้างง่ายหากเราเขียนเมธอดง่ายๆ สัก 2-3 เมธอด เซลล์ฟีดและรายการฟีดเป็นตัวแทนที่แตกต่างกัน 2 แบบสำหรับเนื้อหาเซลล์จริงของเวิร์กชีต ListFeed แสดงข้อมูลทั้งแถวและขอแนะนำให้ใช้ในการโพสต์ข้อมูลใหม่ cellFeed แสดงถึงเซลล์แต่ละเซลล์ และใช้สำหรับการอัปเดตเซลล์แต่ละเซลล์หรือการอัปเดตแบบเป็นกลุ่มไปยังเซลล์แต่ละเซลล์จำนวนมาก (ทั้ง 2 แบบใช้ PUT) โปรดดูรายละเอียดเพิ่มเติมในเอกสารประกอบเกี่ยวกับ Google Spreadsheets API
ก่อนอื่นเราต้องดึงคีย์ของสเปรดชีต (ไฮไลต์ในเอาต์พุต XML ด้านบน) เพื่อรับฟีดเวิร์กชีต
# Extract the spreadsheet key from our datastructure irb(main):040:0> spreadsheet_key = \ irb(main):041:0* doc["entry"][0]["id"][0][/full\/(.*)/, 1] => "o04927555739056712307.3387874275736238738" # Using our get_feed method, let's obtain the worksheet feed irb(main):042:0> worksheet_feed_uri = \ irb(main):043:0* "http://spreadsheets.google.com/feeds/worksheets/#{spreadsheet_key}/private/full" => "http://spreadsheets.google.com/feeds/worksheets/o04927555739056712307.3387874275736238738/private/full" irb(main):044:0> worksheet_response = get_feed(worksheet_feed_uri, headers) => #<Net::HTTPOK 200 OK readbody=true> # Parse the XML into a datastructure irb(main):045:0> worksheet_data = \ irb(main):046:0* XmlSimple.xml_in(worksheet_response.body, 'KeyAttr' => 'name') => {"totalResults"=>["1"], "category"=>[{"term ... [ snip ] # And pretty-print it irb(main):047:0> pp worksheet_data {"totalResults"=>["1"], "category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#worksheet", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "title"=>[{"type"=>"text", "content"=>"blank"}], "author"=> [{"name"=>["test.api.jhartmann"], "email"=>["test.api.jhartmann@gmail.com"]}], "startIndex"=>["1"], "id"=> ["http://spreadsheets.google.com/feeds/worksheets/o04927555739056712307.3387874275736238738/private/full"], "entry"=> [{"category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#worksheet", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "title"=>[{"type"=>"text", "content"=>"Sheet 1"}], "rowCount"=>["100"], "colCount"=>["20"], "id"=> ["http://spreadsheets.google.com/feeds/worksheets/o04927555739056712307.3387874275736238738/private/full/od6"], "content"=>{"type"=>"text", "content"=>"Sheet 1"}, "link"=> [{"href"=> "http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full", "rel"=>"http://schemas.google.com/spreadsheets/2006#listfeed", "type"=>"application/atom+xml"}, {"href"=> "http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full", "rel"=>"http://schemas.google.com/spreadsheets/2006#cellsfeed", "type"=>"application/atom+xml"}, [ snip: cutting off the rest of the XML ]
ดังที่เห็นที่นี่ ตอนนี้เราจะเห็นลิงก์ (highlighted above
) สำหรับเข้าถึง listFeed และ cellsFeed ก่อนที่เราจะเจาะลึก listFeed ขออธิบายสั้นๆ เกี่ยวกับข้อมูลที่มีอยู่ในสเปรดชีตตัวอย่างของเราในขณะนี้ เพื่อให้คุณทราบว่าเรากำลังมองหาอะไร
สเปรดชีตของเราเรียบง่ายมากและมีลักษณะดังนี้
ภาษา | เว็บไซต์ |
---|---|
Java | http://java.com |
php | http://php.net |
และนี่คือลักษณะของข้อมูลนี้ใน ListFeed
irb(main):048:0> listfeed_uri = \ irb(main):049:0* worksheet_data["entry"][0]["link"][0]["href"] => "http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full" irb(main):050:0> response = get_feed(listfeed_uri, headers) => #<Net::HTTPOK 200 OK readbody=true> irb(main):051:0> listfeed_doc = \ irb(main):052:0* XmlSimple.xml_in(response.body, 'KeyAttr' => 'name') => {"totalResults"=>["2"], "category"=>[{"term" ... [ snip ] # Again we parse the XML and then pretty print it irb(main):053:0> pp listfeed_doc {"totalResults"=>["2"], "category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#list", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "title"=>[{"type"=>"text", "content"=>"Programming language links"}], "author"=> [{"name"=>["test.api.jhartmann"], "email"=>["test.api.jhartmann@gmail.com"]}], "startIndex"=>["1"], "id"=> ["http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full"], "entry"=> [{"category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#list", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "language"=>["java"], "title"=>[{"type"=>"text", "content"=>"ruby"}], "website"=>["http://java.com"], "id"=> ["http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cn6ca"], "content"=> {"type"=>"text", "content"=>"website: http://java.com"}, "link"=> [{"href"=> "http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cn6ca", "rel"=>"self", "type"=>"application/atom+xml"}, {"href"=> "http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cn6ca/1j81anl6096", "rel"=>"edit", "type"=>"application/atom+xml"}], "updated"=>["2008-03-20T22:19:51.739Z"]}, {"category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#list", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "language"=>["php"], "title"=>[{"type"=>"text", "content"=>"php"}], "website"=>["http://php.net"], "id"=> ["http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cokwr"], "content"=>{"type"=>"text", "content"=>"website: http://php.net"}, [ snip ]
ดังที่เห็นได้ว่า listFeed จะแสดงเนื้อหาของสเปรดชีตโดยสร้างรายการสำหรับแต่ละแถว โดยจะถือว่าแถวแรกของสเปรดชีตมีส่วนหัวของเซลล์ จากนั้นจะสร้างส่วนหัว XML แบบไดนามิกตามข้อมูลในแถวนั้น การดู XML จริงจะช่วยอธิบายเรื่องนี้ได้เพิ่มเติม
<?xml version='1.0' encoding='UTF-8'?><feed [ snip namespaces ]> <id>http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full</id> <updated>2008-03-20T22:19:51.739Z</updated> <category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/> <title type='text'>Programming language links</title> [ snip: cutting out links and author information ] <entry> <id>http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cn6ca</id> [ snip: updated and category ] <title type='text'>java</title> <content type='text'>website: http://java.com</content> <link rel='self' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cn6ca'/> <link rel='edit' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cn6ca/1j81anl6096'/> <gsx:language>java</gsx:language> <gsx:website>http://java.com</gsx:website> </entry> <entry> <id>http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cokwr</id> [ snip: updated and category ] <title type='text'>php</title> <content type='text'>website: http://php.net</content> <link rel='self' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cokwr'/> <link rel='edit' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full/cokwr/41677fi0nc'/> <gsx:language>php</gsx:language> <gsx:website>http://php.net</gsx:website> </entry> </feed>
มาดูวิธีแสดงข้อมูลเดียวกันใน CellsFeed เพื่อเปรียบเทียบอย่างรวดเร็วกัน
# Extract the cellfeed link irb(main):054:0> cellfeed_uri = \ irb(main):055:0* worksheet_data["entry"][0]["link"][1]["href"] => "http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full" irb(main):056:0> response = \ irb(main):057:0* get_feed(cellfeed_uri, headers) => #<Net::HTTPOK 200 OK readbody=true> # Parse into datastructure and print irb(main):058:0> cellfeed_doc = \ irb(main):059:0* XmlSimple.xml_in(response.body, 'KeyAttr' => 'name') => {"totalResults"=>["6"], [ snip ] irb(main):060:0> pp cellfeed_doc {"totalResults"=>["6"], "category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#cell", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "title"=>[{"type"=>"text", "content"=>"Programming language links"}], "rowCount"=>["101"], "colCount"=>["20"], "author"=> [{"name"=>["test.api.jhartmann"], "email"=>["test.api.jhartmann@gmail.com"]}], "startIndex"=>["1"], "id"=> ["http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full"], "entry"=> [{"category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#cell", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "cell"=> [{"col"=>"1", "row"=>"1", "content"=>"language", "inputValue"=>"language"}], "title"=>[{"type"=>"text", "content"=>"A1"}], "id"=> ["http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R1C1"], "content"=>{"type"=>"text", "content"=>"language"}, "link"=> [{"href"=> "http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R1C1", "rel"=>"self", "type"=>"application/atom+xml"}, {"href"=> "http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R1C1/8srvbs", "rel"=>"edit", "type"=>"application/atom+xml"}], "updated"=>["2008-03-20T22:19:51.739Z"]}, [ snip ]
ดังที่เห็นในภาพนี้ ระบบจะแสดงรายการ 6 รายการ ซึ่งเป็นรายการสำหรับแต่ละเซลล์ ฉันได้ตัดเอาเอาต์พุตอื่นๆ ทั้งหมดออกไปแล้ว เหลือไว้เพียงค่าสำหรับเซลล์ A1 ซึ่งมีคำว่า "ภาษา" นอกจากนี้ โปรดสังเกตลิงก์แก้ไขที่แสดงด้านบน ลิงก์นี้มีสตริงเวอร์ชัน (8srvbs) อยู่ท้ายลิงก์ สตริงเวอร์ชันมีความสำคัญเมื่ออัปเดตข้อมูลเซลล์ ดังที่เราจะทำในตอนท้ายของบทความนี้ ซึ่งช่วยให้มั่นใจได้ว่าการอัปเดตจะไม่ถูกเขียนทับ เมื่อใดก็ตามที่คุณส่งคำขอ PUT เพื่ออัปเดตข้อมูลเซลล์ คุณต้องรวมสตริงเวอร์ชันล่าสุดของเซลล์ไว้ในคำขอ ระบบจะแสดงสตริงเวอร์ชันใหม่หลังจากการอัปเดตแต่ละครั้ง
การโพสต์เนื้อหาไปยัง ListFeed
สิ่งแรกที่เราต้องมีในการโพสต์เนื้อหาคือลิงก์ POST สำหรับ listFeed ระบบจะแสดงลิงก์นี้เมื่อมีการขอฟีดรายการ โดยจะมี URL http://schemas.google.com/g/2005#post
เป็นค่าสำหรับแอตทริบิวต์ rel
คุณจะต้องแยกวิเคราะห์องค์ประกอบลิงก์นี้และดึงแอตทริบิวต์ href
ออกมา ก่อนอื่นเราจะสร้างเมธอดเล็กๆ เพื่อให้การโพสต์ง่ายขึ้น ดังนี้
irb(main):061:0> def post(uri, data, headers) irb(main):062:1> uri = URI.parse(uri) irb(main):063:1> http = Net::HTTP.new(uri.host, uri.port) irb(main):064:1> return http.post(uri.path, data, headers) irb(main):065:1> end => nil # Set up our POST url irb(main):066:0> post_url = \ irb(main):067:0* "http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full" => "http://spreadsheets.google.com/feeds/list/o04927555739056712307.3387874275736238738/od6/private/full" # We must use 'application/atom+xml' as MIME type so let's change our headers # which were still set to 'application/x-www-form-urlencoded' when we sent our # ClientLogin information over https irb(main):068:0> headers["Content-Type"] = "application/atom+xml" => "application/atom+xml" # Setting up our data to post, using proper namespaces irb(main):069:0> new_row = \ irb(main):070:0* '<atom:entry xmlns:atom="http://www.w3.org/2005/Atom">' << irb(main):071:0* '<gsx:language xmlns:gsx="http://schemas.google.com/spreadsheets/2006/extended">' << irb(main):072:0* 'ruby</gsx:language>' << irb(main):073:0* '<gsx:website xmlns:gsx="http://schemas.google.com/spreadsheets/2006/extended">' << irb(main):074:0* 'http://ruby-lang.org</gsx:website>' << irb(main):075:0* '</atom:entry>' => "<atom:entry xmlns:atom=\"http://www.w3.org/2005/Atom\"><gsx:language ... [ snip ] # Performing the post irb(main):076:0> post_response = post(post_url, new_row, headers) => #<Net::HTTPCreated 201 Created readbody=true>
สถานะ 201 แสดงว่าโพสต์ของเราสำเร็จแล้ว
การใช้ cellsFeed เพื่ออัปเดตเนื้อหา
จากเอกสารประกอบ เราเห็นว่าฟีดเซลล์ต้องการคำขอ PUT ในเนื้อหาที่มีอยู่ แต่เนื่องจากข้อมูลที่เราดึงมาจาก CellFeed ก่อนหน้านี้เป็นเพียงข้อมูลที่มีอยู่แล้วในสเปรดชีตจริง เราจะเพิ่มข้อมูลใหม่ได้อย่างไร เราเพียงแค่ต้องส่งคำขอสำหรับแต่ละเซลล์ว่างที่เราต้องการป้อนข้อมูล ข้อมูลโค้ดด้านล่างแสดงวิธีดึงข้อมูลเซลล์ว่าง R5C1 (แถว 5 คอลัมน์ 1) ซึ่งเราต้องการแทรกข้อมูลบางอย่างเกี่ยวกับภาษาโปรแกรม Python
ตัวแปรเดิมของเรา cellfeed_uri
มีเพียง URI สำหรับ Cellfeed เอง ตอนนี้เราต้องการต่อท้ายเซลล์ที่เราต้องการแก้ไขและรับสตริงเวอร์ชันของเซลล์นั้นเพื่อทำการแก้ไข
# Set our query URI irb(main):077:0> cellfeed_query = cellfeed_uri + '/R5C1' => "http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R5C1" # Request the information to extract the edit link irb(main):078:0> cellfeed_data = get_feed(cellfeed_query, headers) => #<Net::HTTPOK 200 OK readbody=true> irb(main):079:0> cellfeed_data.body => "<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gs='http://schemas.google.com/spreadsheets/2006' xmlns:batch='http://schemas.google.com/gdata/batch'>
<id>http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R5C1</id>
<updated>2008-03-24T21:55:36.462Z</updated>
<category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#cell'/>
<title type='text'>A5</title>
<content type='text'>
</content>
<link rel='self' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R5C1'/>
<link rel='edit' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R5C1/47pc'/>
<gs:cell row='5' col='1' inputValue=''>
</gs:cell>
</entry>"
ดังที่เห็นในรายการโค้ดด้านบน สตริงเวอร์ชันคือ 47pc
(คุณอาจต้องเลื่อนไปทางขวาจนสุด) เพื่อให้การทำงานง่ายขึ้น ให้เราสร้างเมธอดที่สะดวกซึ่งจะแสดงสตริงเวอร์ชันสำหรับเซลล์ที่เราสนใจ
irb(main):080:0> def get_version_string(uri, headers=nil) irb(main):081:1> response = get_feed(uri, headers) irb(main):082:1> require 'rexml/document' irb(main):083:1> xml = REXML::Document.new response.body irb(main):084:1> edit_link = REXML::XPath.first(xml, '//[@rel="edit"]') irb(main):085:1> edit_link_href = edit_link.attribute('href').to_s irb(main):086:1> return edit_link_href.split(/\//)[10] irb(main):087:1> end => nil # A quick test irb(main):088:0> puts get_version_string(cellfeed_query, headers) 47pc => nil
ในขณะเดียวกัน เราอาจเขียนเมธอดเพื่อส่งคำขอ PUT ด้วย หรือจะเขียนเมธอดเพื่อทำการอัปเดตแบบเป็นกลุ่มทั้งหมดเลยก็ได้ ฟังก์ชันของเราจะรับอาร์เรย์ของแฮชที่มีตัวแปรต่อไปนี้
:batch_id
- ตัวระบุที่ไม่ซ้ำกันสำหรับคำขอแบบกลุ่มแต่ละรายการ:cell_id
- รหัสของเซลล์ที่จะอัปเดตในรูปแบบ R#C# โดยที่เซลล์ A1 จะแสดงเป็น R1C1:data
- ข้อมูลที่เราต้องการแทรก
irb(main):088:0> def batch_update(batch_data, cellfeed_uri, headers) irb(main):089:1> batch_uri = cellfeed_uri + '/batch' irb(main):090:1> batch_request = <<FEED irb(main):091:1" <?xml version="1.0" encoding="utf-8"?> \ irb(main):092:1" <feed xmlns="http://www.w3.org/2005/Atom" \ irb(main):093:1" xmlns:batch="http://schemas.google.com/gdata/batch" \ irb(main):094:1" xmlns:gs="http://schemas.google.com/spreadsheets/2006" \ irb(main):095:1" xmlns:gd="http://schemas.google.com/g/2005"> irb(main):096:1" <id>#{cellfeed_uri}</id> irb(main):097:1" FEED irb(main):098:1> batch_data.each do |batch_request_data| irb(main):099:2* version_string = get_version_string(cellfeed_uri + '/' + batch_request_data[:cell_id], headers) irb(main):100:2> data = batch_request_data[:data] irb(main):101:2> batch_id = batch_request_data[:batch_id] irb(main):102:2> cell_id = batch_request_data[:cell_id] irb(main):103:2> row = batch_request_data[:cell_id][1,1] irb(main):104:2> column = batch_request_data[:cell_id][3,1] irb(main):105:2> edit_link = cellfeed_uri + '/' + cell_id + '/' + version_string irb(main):106:2> batch_request<< <<ENTRY irb(main):107:2" <entry> irb(main):108:2" <gs:cell col="#{column}" inputValue="#{data}" row="#{row}"/> irb(main):109:2" <batch:id>#{batch_id}</batch:id> irb(main):110:2" <batch:operation type="update" /> irb(main):111:2" <id>#{cellfeed_uri}/#{cell_id}</id> irb(main):112:2" <link href="#{edit_link}" rel="edit" type="application/atom+xml" /> irb(main):113:2" </entry> irb(main):114:2" ENTRY irb(main):115:2> end irb(main):116:1> batch_request << '</feed>' irb(main):117:1> return post(batch_uri, batch_request, headers) irb(main):118:1> end => nil # Our sample batch data to insert information about the Python programming language into our worksheet irb(main):119:0> batch_data = [ \ irb(main):120:0* {:batch_id => 'A', :cell_id => 'R5C1', :data => 'Python'}, \ irb(main):121:0* {:batch_id => 'B', :cell_id => 'R5C2', :data => 'http://python.org' } ] => [{:cell_id=>"R5C1", :data=>"Python", :batch_id=>"A"}=>{:cell_id=>"R5C2", :data=>"http://python.org", :batch_id=>"B"}] # Perform the update irb(main):122:0> response = batch_update(batch_data, cellfeed_uri, headers) => #<Net::HTTPOK 200 OK readbody=true> # Parse the response.body XML and print it irb(main):123:0> response_xml = XmlSimple.xml_in(response.body, 'KeyAttr' => 'name') => [ snip ] irb(main):124:0> pp response_xml {"title"=>[{"type"=>"text", "content"=>"Batch Feed"}], "xmlns:atom"=>"http://www.w3.org/2005/Atom", "id"=> ["http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full"], "entry"=> [{"status"=>[{"code"=>"200", "reason"=>"Success"}], "category"=> [{"term"=>"http://schemas.google.com/spreadsheets/2006#cell", "scheme"=>"http://schemas.google.com/spreadsheets/2006"}], "cell"=> [{"col"=>"1", "row"=>"5", "content"=>"Python", "inputValue"=>"Python"}], "title"=>[{"type"=>"text", "content"=>"A5"}], "id"=> ["http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R5C1", "A"], "operation"=>[{"type"=>"update"}], "content"=>{"type"=>"text", "content"=>"Python"}, "link"=> [{"href"=> "http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R5C1", "rel"=>"self", "type"=>"application/atom+xml"}, {"href"=> "http://spreadsheets.google.com/feeds/cells/o04927555739056712307.3387874275736238738/od6/private/full/R5C1/49kwzg", "rel"=>"edit", "type"=>"application/atom+xml"}], "updated"=>["2008-03-27T15:48:48.470Z"]}, [ snip ]
ดังที่คุณเห็น คำขอแบบกลุ่มของเราสำเร็จแล้วเนื่องจากเราได้รับรหัสการตอบกลับ 200 OK เมื่อแยกวิเคราะห์ XML ของการตอบกลับ เราจะเห็นว่าระบบจะแสดงข้อความแยกต่างหากสำหรับแต่ละ :batch_id
ที่เราตั้งค่าไว้ในอาร์เรย์ response_data
ดูข้อมูลเพิ่มเติมเกี่ยวกับการประมวลผลแบบกลุ่มได้ในเอกสารประกอบการประมวลผลแบบกลุ่มใน GData
บทสรุป
ดังที่เห็น การใช้เชลล์แบบอินเทอร์แอกทีฟของ Ruby เพื่อทดลองใช้ Google Data API นั้นทำได้ง่ายมาก เราเข้าถึงสเปรดชีตและเวิร์กชีตได้โดยใช้ทั้ง listFeed และ cellsFeed นอกจากนี้ เรายังได้แทรกข้อมูลใหม่บางส่วนโดยใช้คำขอ POST จากนั้นเขียนเมธอดเพื่อทำการอัปเดตแบบเป็นกลุ่มโดยใช้โค้ดเพียงประมาณ 120 บรรทัด จากจุดนี้ คุณไม่ควรพบกับความยากลำบากในการรวมวิธีการง่ายๆ เหล่านี้เข้ากับคลาสและสร้างเฟรมเวิร์กที่นำกลับมาใช้ซ้ำได้
โปรดเข้าร่วมกลุ่มสนทนาหากมีข้อสงสัยเกี่ยวกับการใช้เครื่องมือเหล่านี้กับ Google Data API ที่คุณชื่นชอบ
คุณดูไฟล์คลาสที่มีตัวอย่างโค้ดที่อธิบายไว้ข้างต้นได้ที่ http://code.google.com/p/google-data-samples-ruby