Google Data API के साथ Ruby का इस्तेमाल करना

जोचेन हार्टमैन, Google Data APIs टीम
अप्रैल 2008

परिचय

Ruby, एक डाइनैमिक स्क्रिप्टिंग भाषा है. पिछले कुछ सालों में, यह काफ़ी लोकप्रिय हुई है. इसकी वजह, Rails वेब-डेवलपमेंट फ़्रेमवर्क है. इस लेख में, Google Data API सेवाओं के साथ इंटरैक्ट करने के लिए, Ruby का इस्तेमाल करने का तरीका बताया गया है. हम Rails पर फ़ोकस नहीं करेंगे. इसके बजाय, हम एचटीटीपी कमांड और फ़ीड के स्ट्रक्चर के बारे में ज़्यादा जानकारी देंगे. यहां दिए गए सभी उदाहरणों को कमांड लाइन से फ़ॉलो किया जा सकता है. इसके लिए, Ruby के इंटरैक्टिव शेल irb का इस्तेमाल करें.

आपको cURL लेख से याद होगा कि Google Data API, वेब संसाधनों को दिखाने, बनाने, और अपडेट करने के लिए Atom Publishing Protocol का इस्तेमाल करते हैं. इस प्रोटोकॉल की सबसे अच्छी बात यह है कि अनुरोधों को तैयार करने के लिए, स्टैंडर्ड एचटीटीपी वर्ब का इस्तेमाल किया जाता है. साथ ही, इनके जवाब स्टैंडर्ड एचटीटीपी स्टेटस कोड के ज़रिए दिए जाते हैं.

इस लेख में, हम इन क्रियाओं का इस्तेमाल करेंगे: कॉन्टेंट पाने के लिए GET, नया कॉन्टेंट अपलोड करने के लिए POST, और मौजूदा कॉन्टेंट को अपडेट करने के लिए PUT. Google Data API का इस्तेमाल करते समय, आपको कुछ स्टैंडर्ड कोड दिख सकते हैं. जैसे, फ़ीड या एंट्री को वापस पाने में सफलता दिखाने के लिए 200 या किसी संसाधन को बनाने या अपडेट करने में सफलता दिखाने के लिए 201. अगर कोई गड़बड़ी होती है, जैसे कि गलत तरीके से किया गया अनुरोध भेजा जाता है, तो 400 कोड (इसका मतलब है 'गलत अनुरोध') वापस भेजा जाएगा. जवाब के मुख्य हिस्से में ज़्यादा जानकारी वाला मैसेज दिया जाएगा. इसमें बताया जाएगा कि असल में क्या गड़बड़ी हुई है.

Ruby, 'Net' मॉड्यूल के तहत एक बेहतरीन डीबगिंग विकल्प उपलब्ध कराता है. इन कोड के सैंपल को छोटा रखने के लिए, मैंने यहां इसे चालू नहीं किया है.

Ruby को पाना और इंस्टॉल करना

अगर Linux का इस्तेमाल किया जा रहा है, तो Ruby को ज़्यादातर पैकेज मैनेजमेंट सिस्टम का इस्तेमाल करके इंस्टॉल किया जा सकता है. अन्य ऑपरेटिंग सिस्टम के लिए और पूरा सोर्स कोड पाने के लिए, कृपया http://www.ruby-lang.org/en/downloads/ पर जाएं. Irb, इंटरैक्टिव शेल है. हम इन उदाहरणों के लिए इसका इस्तेमाल करेंगे. यह डिफ़ॉल्ट रूप से इंस्टॉल होना चाहिए. यहां दिए गए कोड के उदाहरणों को समझने के लिए, आपको XmlSimple भी इंस्टॉल करना होगा. यह एक छोटी लाइब्रेरी है, जो एक्सएमएल को रूबी डेटास्ट्रक्चर में पार्स करती है. XmlSimple को पाने/इंस्टॉल करने के लिए, कृपया http://xml-simple.rubyforge.org/ पर जाएं

अपने सिस्टम पर Ruby की कॉपी चलाने के बाद, Google की डेटा सेवाओं से बुनियादी अनुरोध करने के लिए, Net:HTTP पैकेज का इस्तेमाल किया जा सकता है. यहां दिए गए स्निपेट में, Ruby के इंटरैक्टिव शेल से ज़रूरी इंपोर्ट करने का तरीका बताया गया है. हम 'net/http' पैकेज का इस्तेमाल कर रहे हैं. साथ ही, YouTube पर सबसे ज़्यादा रेटिंग वाले वीडियो फ़ीड के यूआरएल को पार्स कर रहे हैं. इसके बाद, हम एचटीटीपी 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>

इस अनुरोध से, कमांड लाइन पर काफ़ी एक्सएमएल दिखना चाहिए. आपने देखा होगा कि सभी आइटम, <feed> एलिमेंट में शामिल हैं और इन्हें <entry> एलिमेंट कहा जाता है. अभी एक्सएमएल फ़ॉर्मैटिंग के बारे में चिंता न करें. हमें सिर्फ़ यह बताना था कि एचटीटीपी का इस्तेमाल करके, Google Data API के लिए बुनियादी अनुरोध कैसे किया जाता है. अब हम एपीआई बदलेंगे और स्प्रेडशीट पर फ़ोकस करेंगे, क्योंकि हम जो जानकारी भेज और वापस पा सकते हैं वह 'कमांड-लाइन के हिसाब से ज़्यादा सही' है.

पुष्टि करना | Google Spreadsheets API का इस्तेमाल करना

हम एंट्री एलिमेंट का फ़ीड फिर से पाने से शुरुआत करेंगे. हालांकि, इस बार हमें अपनी स्प्रैडशीट के साथ काम करना है. इसके लिए, हमें सबसे पहले Google Accounts सेवा से पुष्टि करनी होगी.

आपको GData Authentication के दस्तावेज़ से याद होगा कि Google की सेवाओं के साथ पुष्टि करने के दो तरीके हैं. 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 - [email protected]</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>[email protected]</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 स्प्रेडशीट हैं. इस लेख को छोटा रखने के लिए, मैंने ऊपर दिए गए बाकी एक्सएमएल आउटपुट को काट दिया है. ऐसा मैंने ज़्यादातर अन्य लिस्टिंग में भी किया है. इस स्प्रेडशीट के बारे में ज़्यादा जानने के लिए, हमें कुछ और चरणों को पूरा करना होगा:

  1. स्प्रेडशीट की कुंजी पाना
  2. हमारी वर्कशीट का फ़ीड पाने के लिए, स्प्रेडशीट कुंजी का इस्तेमाल करें
  3. उस वर्कशीट का आईडी पाएं जिसका हमें इस्तेमाल करना है
  4. वर्कशीट के असली कॉन्टेंट को ऐक्सेस करने के लिए, cellsFeed या listFeed का अनुरोध करें

यह आपको बहुत मुश्किल लग सकता है, लेकिन हम आपको दिखाएंगे कि कुछ आसान तरीके लिखने से यह सब कितना आसान हो जाता है. cellsFeed और listFeed, किसी वर्कशीट के सेल कॉन्टेंट को दिखाने के दो अलग-अलग तरीके हैं. listFeed, जानकारी की पूरी लाइन को दिखाता है. नए डेटा को POST करने के लिए, इसका इस्तेमाल करने का सुझाव दिया जाता है. CellFeed, अलग-अलग सेल को दिखाता है. इसका इस्तेमाल, अलग-अलग सेल को अपडेट करने या कई अलग-अलग सेल को एक साथ अपडेट करने के लिए किया जाता है. दोनों के लिए PUT का इस्तेमाल किया जाता है. ज़्यादा जानकारी के लिए, कृपया Google Sheets API का दस्तावेज़ देखें.

वर्कशीट फ़ीड पाने के लिए, हमें सबसे पहले स्प्रेडशीट की (ऊपर एक्सएमएल आउटपुट में हाइलाइट की गई) निकालनी होगी:

# 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"=>["[email protected]"]}],
 "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 ]

जैसा कि यहां देखा जा सकता है, अब हमें listFeed और cellsFeed को ऐक्सेस करने के लिए लिंक (highlighted above) मिल सकते हैं. listFeed के बारे में जानने से पहले, आइए हम आपको यह बता दें कि हमारे सैंपल स्प्रेडशीट में फ़िलहाल कौन-कौनसा डेटा मौजूद है, ताकि आपको पता चल सके कि हमें किस तरह का डेटा चाहिए:

हमारी स्प्रेडशीट बहुत आसान है और कुछ इस तरह दिखती है:

भाषावेबसाइट
javahttp://java.com
phphttp://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"=>["[email protected]"]}],
 "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 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"=>["[email protected]"]}],
 "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 में कॉन्टेंट पोस्ट करना

कॉन्टेंट पोस्ट करने के लिए, हमें सबसे पहले listFeed के लिए POST लिंक की ज़रूरत होती है. सूची वाले फ़ीड का अनुरोध करने पर, यह लिंक वापस भेज दिया जाएगा. इसमें rel एट्रिब्यूट की वैल्यू के तौर पर यूआरएल 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 स्टेटस से पता चलता है कि हमारी पोस्ट सफल रही.

कॉन्टेंट अपडेट करने के लिए, cellsFeed का इस्तेमाल करना

दस्तावेज़ से पता चलता है कि सेल फ़ीड, मौजूदा कॉन्टेंट पर PUT अनुरोधों को प्राथमिकता देता है. हालांकि, ऊपर दिए गए सेल्स फ़ीड से हमें सिर्फ़ वह डेटा मिला जो हमारी स्प्रेडशीट में पहले से मौजूद था. ऐसे में, नई जानकारी कैसे जोड़ी जा सकती है? हमें सिर्फ़ हर उस खाली सेल के लिए अनुरोध करना होगा जिसमें हमें डेटा डालना है. नीचे दिए गए स्निपेट में, खाली सेल R5C1 (पांचवीं लाइन, पहला कॉलम) को वापस पाने का तरीका दिखाया गया है. हमें इस सेल में Python प्रोग्रामिंग भाषा के बारे में कुछ जानकारी डालनी है.

हमारे ओरिजनल वैरिएबल cellfeed_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 OK रिस्पॉन्स कोड मिला है. जवाब के एक्सएमएल को पार्स करने पर, हमें पता चलता है कि हर :batch_id के लिए एक अलग मैसेज मिलता है. यह :batch_id, हमने response_data ऐरे में सेट किया था. बैच प्रोसेसिंग के बारे में ज़्यादा जानकारी के लिए, कृपया GData में बैच प्रोसेसिंग दस्तावेज़ देखें.

नतीजा

जैसा कि आपने देखा, Google Data API के साथ काम करने के लिए, Ruby के इंटरैक्टिव शेल का इस्तेमाल करना बहुत आसान है. हम listFeed और cellsFeed, दोनों का इस्तेमाल करके अपनी स्प्रेडशीट और वर्कशीट ऐक्सेस कर सकते थे. इसके अलावा, हमने POST अनुरोध का इस्तेमाल करके कुछ नया डेटा डाला है. इसके बाद, हमने बैच अपडेट करने के लिए तरीके लिखे हैं. इसके लिए, सिर्फ़ 120 लाइनों के कोड का इस्तेमाल किया गया है. इसके बाद, इन आसान तरीकों को क्लास में रैप करना और दोबारा इस्तेमाल किया जा सकने वाला फ़्रेमवर्क बनाना ज़्यादा मुश्किल नहीं होना चाहिए.

अगर आपको अपने पसंदीदा Google Data API के साथ इन टूल का इस्तेमाल करने के बारे में कोई सवाल पूछना है, तो कृपया हमारे discussion groups में शामिल हों.

ऊपर दिए गए कोड सैंपल वाली क्लास फ़ाइल, http://code.google.com/p/google-data-samples-ruby पर देखी जा सकती है

इस लेख के बारे में चर्चा करें!