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

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

सुविधा के बारे में जानकारी

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

जैसा कि आपको cURL लेख से याद होगा, Google Data API वेब संसाधन दिखाने, बनाने, और उन्हें अपडेट करने के लिए, ऐटम पब्लिशिंग प्रोटोकॉल का इस्तेमाल करता है. इस प्रोटोकॉल की सुंदरता यह है कि मानक HTTP क्रियाओं का इस्तेमाल ऐसे अनुरोध तैयार करने के लिए किया जाता है जिनका जवाब मानक HTTP स्थिति कोड के साथ दिया जाता है.

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

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

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

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

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

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

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

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

जैसा कि आपको GData प्रमाणीकरण में दिए गए दस्तावेज़ से याद आ सकता है, Google सेवाओं के साथ प्रमाणीकरण करने के दो तरीके हैं. AuthSub वेब-आधारित ऐप्लिकेशन के लिए है और कम शब्दों में, इसमें टोकन-एक्सचेंज की प्रोसेस शामिल है. AuthSub का असल फ़ायदा यह है कि आपके ऐप्लिकेशन को उपयोगकर्ता क्रेडेंशियल सेव करने की ज़रूरत नहीं होती है. ClientLogin, "इंस्टॉल किए गए" ऐप्लिकेशन के लिए है. ClientLogin प्रक्रिया में, Google की सेवाओं को https के माध्यम से उपयोगकर्ता नाम और पासवर्ड के साथ एक स्ट्रिंग भेजी जाती है जो उस सेवा की पहचान करती है जिसका आप उपयोग करना चाहते हैं. Google Spreadsheets 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 स्प्रेडशीट हैं. इस लेख को छोटा रखने के लिए, मैंने ऊपर दिए गए बाकी एक्सएमएल आउटपुट को काट दिया है (साथ ही, ज़्यादातर दूसरी लिस्टिंग में भी). इस स्प्रेडशीट की ज़्यादा जानकारी के लिए, हमें कुछ और चरण पूरे करने होंगे:

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

ऐसा लग सकता है कि यह काम काफ़ी आसान है. हालांकि, अगर हम कुछ आसान तरीके लिखते हैं, तो हम आपको बताएंगे कि यह तरीका काफ़ी आसान है. सेलफ़ीड और listFeed, वर्कशीट की असल सेल के कॉन्टेंट को दो अलग-अलग तरह से दिखाते हैं. listFeed जानकारी की एक पूरी पंक्ति दिखाता है. साथ ही, हमारा सुझाव है कि नया डेटा पोस्ट करें. सेलफ़ीड अलग-अलग सेल के बारे में बताता है. इसका इस्तेमाल, अलग-अलग सेल अपडेट या अलग-अलग सेल के बैच अपडेट (दोनों को पीयूटी का इस्तेमाल करके) के लिए किया जाता है. ज़्यादा जानकारी के लिए, कृपया Google Spreadsheets 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"=>["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 ]

जैसा कि यहां देखा जा सकता है, अब हमें listFeed औरcellFeed को ऐक्सेस करने के लिए, लिंक (highlighted above) मिल गए हैं. listFeed के बारे में गहराई से जानने से पहले, मुझे यह समझाएं कि हमारी नमूना स्प्रैडशीट में वर्तमान में कौन सा डेटा मौजूद है, ताकि आपको पता चल जाए कि हम क्या खोज रहे हैं:

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

भाषावेबसाइट
Javahttp://java.com
phphttp://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 ]

जैसा कि आप देख सकते हैं, 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"=>["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 की वैल्यू के अलावा, दूसरे सभी आउटपुट को काट दिया है. इसमें 'भाषा' शब्द मौजूद है. साथ ही, ऊपर दिखाए गए बदलाव करें लिंक पर भी ध्यान दें. इस लिंक के आखिर में एक वर्शन स्ट्रिंग (8srbs) मौजूद है. सेल डेटा को अपडेट करते समय वर्शन स्ट्रिंग ज़रूरी होती है, जैसा कि हम इस लेख के आखिर में करेंगे. इससे यह पक्का होता है कि अपडेट ओवरराइट नहीं होते हैं. सेल डेटा को अपडेट करने के लिए जब आप एक PUT अनुरोध कर रहे हों, तो आपको अपने अनुरोध में सेल की सबसे हाल की वर्शन स्ट्रिंग शामिल करनी होगी. हर अपडेट के बाद, नए वर्शन की स्ट्रिंग दिखेगी.

listFeed में सामग्री पोस्ट कर रहा है

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

कॉन्टेंट अपडेट करने के लिए सेल फ़ीड का इस्तेमाल करना

दस्तावेज़ में यह देखा जा सकता है कि सेल फ़ीड मौजूदा कॉन्टेंट पर PUT अनुरोधों को प्राथमिकता देता है. हालांकि, ऊपर दी गई सेलफ़ीड से मिली जानकारी, सिर्फ़ हमारी वास्तविक स्प्रेडशीट का पहले से मौजूद डेटा है. इसलिए, हम नई जानकारी कैसे जोड़ सकते हैं? हमें हर उस खाली सेल के लिए अनुरोध करना होगा जिसमें हम डेटा डालना चाहते हैं. नीचे दिए गए स्निपेट में खाली सेल R5C1 (पंक्ति 5, कॉलम 1) को वापस पाने का तरीका बताया गया है. इसमें हम 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 जवाब कोड मिल गया था. रिस्पॉन्स एक्सएमएल को पार्स करते समय, हम देख सकते हैं कि हमने अपनी response_data कैटगरी में जो भी :batch_id सेट किया है उसके लिए एक अलग मैसेज दिखता है. बैच प्रोसेसिंग के बारे में ज़्यादा जानकारी के लिए, कृपया GData में बैच प्रोसेसिंग दस्तावेज़ देखें.

नतीजा

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

अगर इन टूल को इस्तेमाल करने के बारे में आपका कोई पसंदीदा सवाल है, तो कृपया चर्चा समूहों में हमसे जुड़ें.

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

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