Google ডেটা API-এর সাথে রুবি ব্যবহার করা

Jochen Hartmann, Google Data APIs টিম
এপ্রিল 2008

ভূমিকা

রুবি হল একটি গতিশীল স্ক্রিপ্টিং ভাষা যা সাম্প্রতিক বছরগুলিতে জনপ্রিয় রেল ওয়েব-ডেভেলপমেন্ট ফ্রেমওয়ার্কের কারণে যথেষ্ট মনোযোগ পেয়েছে। এই নিবন্ধটি ব্যাখ্যা করবে কিভাবে রুবি ব্যবহার করে Google Data API পরিষেবার সাথে ইন্টারঅ্যাক্ট করতে হয়। আমরা রেলের উপর ফোকাস করব না, পরিবর্তে আমরা আমাদের ফিডগুলির অন্তর্নিহিত HTTP কমান্ড এবং কাঠামো ব্যাখ্যা করতে আরও আগ্রহী। এখানে উপস্থাপিত সমস্ত উদাহরণ irb , রুবির ইন্টারেক্টিভ শেল ব্যবহার করে কমান্ড লাইন থেকে অনুসরণ করা যেতে পারে।

আপনি cURL নিবন্ধ থেকে মনে করতে পারেন, Google Data APIs ওয়েব রিসোর্স উপস্থাপন, তৈরি এবং আপডেট করার জন্য অ্যাটম পাবলিশিং প্রোটোকল ব্যবহার করে। এই প্রোটোকলের সৌন্দর্য হল যে স্ট্যান্ডার্ড HTTP ক্রিয়াগুলি অনুরোধগুলি তৈরি করতে ব্যবহৃত হয় যা স্ট্যান্ডার্ড HTTP স্ট্যাটাস কোডগুলির সাথে উত্তর দেওয়া হয়।

এই নিবন্ধে আমরা যে ক্রিয়াপদগুলি ব্যবহার করব তা হল সামগ্রী পুনরুদ্ধার করতে GET , নতুন সামগ্রী আপলোড করার জন্য POST এবং বিদ্যমান সামগ্রী আপডেট করার জন্য PUT ৷ কিছু স্ট্যান্ডার্ড কোড যা আপনি Google Data APIs ব্যবহার করে দেখতে পারেন সেগুলি হল 200 একটি ফিড বা একটি এন্ট্রি পুনরুদ্ধারে সাফল্যের প্রতিনিধিত্ব করার জন্য, অথবা 201 একটি সম্পদের সফল সৃষ্টি বা আপডেটের প্রতিনিধিত্ব করার জন্য৷ যদি কিছু ভুল হয়ে যায়, যেমন একটি বিকৃত অনুরোধ পাঠানো হলে, একটি 400 কোড (অর্থাৎ 'খারাপ অনুরোধ') ফেরত পাঠানো হবে। ঠিক কী ভুল হয়েছে তা ব্যাখ্যা করে প্রতিক্রিয়া বডিতে আরও বিস্তারিত বার্তা দেওয়া হবে।

রুবি 'নেট' মডিউলের অংশ হিসাবে একটি চমৎকার ডিবাগিং বিকল্প প্রদান করে। এই কোড নমুনাগুলি যুক্তিসঙ্গতভাবে সংক্ষিপ্ত রাখার স্বার্থে, আমি এখানে এটি সক্ষম করিনি।

রুবি প্রাপ্ত এবং ইনস্টল করা

আপনি যদি লিনাক্স ব্যবহার করেন তবে বেশিরভাগ প্যাকেজ ম্যানেজমেন্ট সিস্টেম ব্যবহার করে রুবি ইনস্টল করা যেতে পারে। অন্যান্য অপারেটিং সিস্টেমের জন্য এবং সম্পূর্ণ সোর্স কোড পেতে, দয়া করে http://www.ruby-lang.org/en/downloads/ এ যান। Irb , ইন্টারেক্টিভ শেল যা আমরা এই উদাহরণগুলির জন্য ব্যবহার করতে যাচ্ছি ডিফল্টরূপে ইনস্টল করা উচিত। এখানে তালিকাভুক্ত কোড উদাহরণগুলি অনুসরণ করতে, আপনাকে XmlSimple ইনস্টল করতে হবে, একটি ছোট লাইব্রেরি XML কে রুবি ডেটাস্ট্রাকচারে পার্স করতে। XmlSimple পেতে/ইনস্টল করতে, অনুগ্রহ করে ভিজিট করুন http://xml-simple.rubyforge.org/

একবার আপনার মেশিনে রুবির একটি কপি চললে, আপনি Google-এর ডেটা পরিষেবাগুলিতে প্রাথমিক অনুরোধ করতে Net:HTTP প্যাকেজ ব্যবহার করতে পারেন। নিচের স্নিপেটটি দেখায় কিভাবে রুবির ইন্টারেক্টিভ শেল থেকে প্রয়োজনীয় আমদানি করতে হয়। আমরা যা করছি তা হল 'নেট/এইচটিটিপি' প্যাকেজ প্রয়োজন, ইউটিউব থেকে শীর্ষ রেট করা ভিডিও ফিডের URL পার্স করা এবং তারপর একটি 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 ফর্ম্যাটিং নিয়ে চিন্তা না করি, আমি শুধু ব্যাখ্যা করতে চেয়েছিলাম কিভাবে HTTP ব্যবহার করে একটি মৌলিক Google Data API অনুরোধ করা যায়। আমরা এখন API গুলি স্যুইচ করতে যাচ্ছি এবং স্প্রেডশীটগুলিতে ফোকাস করতে যাচ্ছি, যেহেতু আমরা যে তথ্য পাঠাতে এবং পুনরুদ্ধার করতে পারি তা আরও 'কমান্ড-লাইন বন্ধুত্বপূর্ণ'।

প্রমাণীকরণ | Google স্প্রেডশীট API ব্যবহার করে

আমরা আবার এন্ট্রি উপাদানগুলির একটি ফিড পুনরুদ্ধার করে শুরু করব। এই সময় যদিও আমরা আমাদের নিজস্ব স্প্রেডশীট নিয়ে কাজ করতে চাই। এটি করার জন্য, আমাদের প্রথমে Google অ্যাকাউন্ট পরিষেবার সাথে প্রমাণীকরণ করতে হবে৷

আপনি GData প্রমাণীকরণের ডকুমেন্টেশন থেকে মনে করতে পারেন, Google এর পরিষেবাগুলির সাথে প্রমাণীকরণের দুটি উপায় রয়েছে। AuthSub হল ওয়েব-ভিত্তিক অ্যাপ্লিকেশনের জন্য এবং সংক্ষেপে একটি টোকেন-বিনিময় প্রক্রিয়া জড়িত। AuthSub এর আসল সুবিধা হল যে আপনার অ্যাপ্লিকেশনটিকে ব্যবহারকারীর শংসাপত্র সংরক্ষণ করার প্রয়োজন নেই। ClientLogin "ইনস্টল করা" অ্যাপ্লিকেশনের জন্য। ক্লায়েন্টলগইন প্রক্রিয়ায়, ব্যবহারকারীর নাম এবং পাসওয়ার্ড একটি স্ট্রিং সহ https এর মাধ্যমে Google এর পরিষেবাগুলিতে পাঠানো হয় যা আপনি যে পরিষেবাটি ব্যবহার করতে চাইছেন তা সনাক্ত করে৷ Google স্প্রেডশীট API পরিষেবাটি স্ট্রিং ওয়াইজ দ্বারা চিহ্নিত করা হয়।

আমাদের ইন্টারেক্টিভ শেলে ফিরে যাচ্ছি, আসুন 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> ...

আবার আমরা অনেকগুলি এক্সএমএল দেখছি যা আমি উপরে ডি-জোর করেছি কারণ আপনাকে কমান্ড লাইন থেকে এটি বোঝার বিষয়ে চিন্তা করার দরকার নেই। জিনিসগুলিকে আরও ব্যবহারকারী-বান্ধব করতে, আসুন পরিবর্তে 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 আউটপুটটি কেটে দিয়েছি (পাশাপাশি অন্যান্য তালিকায়)। এই স্প্রেডশীটের গভীরে খনন করতে, আমাদের আরও কয়েকটি ধাপ সম্পাদন করতে হবে:

  1. স্প্রেডশীট কী পান
  2. আমাদের ওয়ার্কশীট ফিড পেতে স্প্রেডশীট কী ব্যবহার করুন
  3. আমরা যে ওয়ার্কশীট ব্যবহার করতে চাই তার জন্য আইডি পান
  4. কার্যপত্রকের প্রকৃত বিষয়বস্তু অ্যাক্সেস করার জন্য সেলফিড বা তালিকাফিডকে অনুরোধ করুন

এটি অনেক কাজের মতো মনে হতে পারে তবে আমি আপনাকে দেখাব যে এটি বেশ সহজ যদি আমরা কয়েকটি সহজ পদ্ধতি লিখি। সেলফিড এবং লিস্টফিড একটি ওয়ার্কশীটের প্রকৃত সেল সামগ্রীর জন্য দুটি ভিন্ন উপস্থাপনা। লিস্টফিড তথ্যের একটি সম্পূর্ণ সারি উপস্থাপন করে এবং নতুন ডেটা পোস্ট করার জন্য সুপারিশ করা হয়। সেলফিড পৃথক কোষের প্রতিনিধিত্ব করে এবং এটি পৃথক সেল আপডেটের জন্য ব্যবহৃত হয় বা অনেকগুলি পৃথক কোষের ব্যাচ আপডেটের জন্য (উভয়ই PUT ব্যবহার করে)। আরও বিস্তারিত জানার জন্য অনুগ্রহ করে Google স্প্রেডশীট 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 ) খুঁজে পেতে পারি। লিস্টফিডে খনন করার আগে, আমাদের নমুনা স্প্রেডশীটে বর্তমানে কোন ডেটা বিদ্যমান রয়েছে তা আমাকে দ্রুত ব্যাখ্যা করতে দিন যাতে আপনি জানতে পারবেন আমরা কী খুঁজছি:

আমাদের স্প্রেডশীট খুব সহজ এবং ঠিক এই মত দেখায়:

ভাষা ওয়েবসাইট
জাভা http://java.com
php http://php.net

এবং লিস্টফিডে এই ডেটাটি দেখতে কেমন তা এখানে:

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 ]

আপনি দেখতে পাচ্ছেন, লিস্টফিড প্রতিটি সারির জন্য একটি এন্ট্রি তৈরি করে আপনার ওয়ার্কশীটের বিষয়বস্তু ফেরত দেয়। এটি অনুমান করে যে স্প্রেডশীটের প্রথম সারিতে আপনার সেল হেডার রয়েছে এবং তারপর সেই সারির ডেটার উপর ভিত্তি করে গতিশীলভাবে 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>

একটি দ্রুত তুলনা করার জন্য, আসুন দেখুন কিভাবে একই তথ্য সেলফিডে উপস্থাপন করা হয়:

# 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 অনুরোধ করছেন, আপনাকে অবশ্যই আপনার অনুরোধে সেলের সর্বশেষ সংস্করণ স্ট্রিং অন্তর্ভুক্ত করতে হবে৷ প্রতিটি আপডেটের পরে একটি নতুন সংস্করণ স্ট্রিং ফিরে আসবে।

লিস্টফিডে কন্টেন্ট পোস্ট করা

বিষয়বস্তু পোস্ট করার জন্য আমাদের প্রথম যে জিনিসটি প্রয়োজন তা হল লিস্টফিডের জন্য পোস্ট লিঙ্ক। তালিকা ফিড অনুরোধ করা হলে এই লিঙ্ক ফেরত দেওয়া হবে. এতে rel অ্যাট্রিবিউটের মান হিসেবে URL http://schemas.google.com/g/2005#post থাকবে। আপনাকে এই লিঙ্ক উপাদানটি পার্স করতে হবে এবং এর 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 স্ট্যাটাস নির্দেশ করে যে আমাদের পোস্ট সফল হয়েছে।

কন্টেন্ট আপডেট করতে সেলফিড ব্যবহার করে

ডকুমেন্টেশন থেকে আমরা দেখতে পাচ্ছি যে সেল ফিড বিদ্যমান সামগ্রীতে PUT অনুরোধগুলিকে পছন্দ করে। কিন্তু যেহেতু উপরের সেলফিড থেকে আমরা যে তথ্যটি পুনরুদ্ধার করেছি তা কেবলমাত্র সেই ডেটা যা ইতিমধ্যেই আমাদের প্রকৃত স্প্রেডশীটে ছিল, আমরা কীভাবে নতুন তথ্য যোগ করতে পারি? আমাদের প্রতিটি খালি কক্ষের জন্য একটি অনুরোধ করতে হবে যেখানে আমরা ডেটা প্রবেশ করতে চাই। নীচের স্নিপেটটি দেখায় যে কীভাবে খালি সেল R5C1 (সারি 5, কলাম 1) পুনরুদ্ধার করা যায় যেখানে আমরা পাইথন প্রোগ্রামিং ভাষা সম্পর্কে কিছু তথ্য সন্নিবেশ করতে চাই।

আমাদের আসল পরিবর্তনশীল cellfeed_uri সেলফিডের জন্যই শুধুমাত্র URI রয়েছে। আমরা এখন যে কোষটিকে আমরা সম্পাদনা করতে চাইছি সেটি যুক্ত করতে চাই এবং আমাদের সম্পাদনা করতে সেই কোষ সংস্করণ স্ট্রিংটি পেতে চাই:

# 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 ওকে রেসপন্স কোড পেয়েছি। রেসপন্স এক্সএমএল পার্স করে, আমরা দেখতে পাচ্ছি যে প্রতিটি ব্যক্তির জন্য একটি আলাদা বার্তা দেওয়া হয়েছে :batch_id যা আমরা আমাদের response_data অ্যারেতে সেট করেছি। ব্যাচ প্রসেসিং সম্পর্কে আরও তথ্যের জন্য, অনুগ্রহ করে GData ডকুমেন্টেশনে ব্যাচ প্রসেসিং পড়ুন।

উপসংহার

আপনি যেমন দেখেছেন, Google Data API-এর সাথে খেলার জন্য রুবির ইন্টারেক্টিভ শেল ব্যবহার করা খুবই সহজ। আমরা লিস্টফিড এবং সেলফিড উভয় ব্যবহার করে আমাদের স্প্রেডশীট এবং ওয়ার্কশীটগুলি অ্যাক্সেস করতে সক্ষম হয়েছি। উপরন্তু আমরা একটি POST অনুরোধ ব্যবহার করে কিছু নতুন ডেটা সন্নিবেশ করেছি এবং তারপরে কোডের প্রায় 120 লাইনের সাথে একটি ব্যাচ আপডেট করার জন্য লিখিত পদ্ধতি। এই মুহূর্ত থেকে এই সহজ পদ্ধতিগুলির কয়েকটি ক্লাসে মোড়ানো এবং নিজেকে একটি পুনরায় ব্যবহারযোগ্য কাঠামো তৈরি করা খুব কঠিন হওয়া উচিত নয়।

আপনার প্রিয় Google Data API এর সাথে এই টুলগুলি ব্যবহার করার বিষয়ে আপনার কোন প্রশ্ন থাকলে অনুগ্রহ করে আলোচনা গোষ্ঠীতে আমাদের সাথে যোগ দিন।

উপরে বিস্তারিত কোড নমুনা সহ একটি ক্লাস ফাইল http://code.google.com/p/google-data-samples-ruby- এ পাওয়া যাবে

এই নিবন্ধটি আলোচনা!