Yakut'u Google Veri API'larıyla kullanma

Jochen Hartmann, Google Veri API'leri Ekibi
Nisan 2008

Giriş

Yakut, popüler Rails web geliştirme çerçevesi nedeniyle son yıllarda oldukça ilgi gören dinamik bir kodlama dilidir. Bu makalede, Google Data API hizmetleriyle etkileşime geçmek için Roku'nun nasıl kullanılacağı açıklanmaktadır. Rails'e odaklanmayacağız. Bunun yerine, feed'lerimizin altında yatan HTTP komutlarını ve yapısını açıklamak istiyoruz. Burada sunulan tüm örnekler, Rutin'in etkileşimli kabuğu irb kullanılarak komut satırından takip edilebilir.

cURL makalesinde hatırlayabileceğiniz gibi Google Veri API'ları, web kaynaklarını temsil etmek, oluşturmak ve güncellemek için Atom Yayınlama Protokolü'nü kullanır. Bu protokolün güzel yanı, standart HTTP durum kodlarıyla yanıtlanmış istekleri formüle etmek için standart HTTP fiillerinin kullanılmasıdır.

Bu makalede, yükleyeceğiniz içerikleri GET, yeni içeriği yüklemek için POST ve mevcut içeriği güncellemek için PUT ifadeleri kullanacağız. Google Veri API'larını kullanırken karşılaşabileceğiniz standart kodların bazıları, bir feed'i veya girişi alma başarısını temsil etmek için 200 veya bir kaynağın başarıyla oluşturulmasını ya da güncellenmesini temsil etmek için 201'dir. Hatalı bir istek gönderildiğinde (örneğin, hatalı bir istek gönderildiğinde) sorun yaşarsanız 400 kodu ("Hatalı İstek" anlamına gelir) geri gönderilir. Yanıt gövdesinde, sorunun tam olarak ne olduğunu açıklayan daha ayrıntılı bir mesaj sağlanır.

Yakut, "Net" modülü kapsamında güzel bir hata ayıklama seçeneği sunar. Bu kod örneklerini makul ölçüde kısa tutmak için burada etkinleştirmedim.

Yakut'u edinme ve yükleme

Linux kullanıyorsanız çoğu paket yönetimi sistemi kullanılarak Yakut yüklenebilir. Diğer işletim sistemleri ve tam kaynak kodu için lütfen http://www.ruby-lang.org/en/downloads/ adresini ziyaret edin. Bu örnekler için kullanacağımız etkileşimli kabuk, varsayılan olarak Irb'dan yüklenmelidir. Burada listelenen kod örneklerini izlemek için XML'yi Yakut veri yapılarına ayrıştıracak küçük bir kitaplık olan XmlSimple aracını da yüklemeniz gerekir. Xml Simple'ı edinmek/yüklemek için lütfen http://xml-basit.rubyforge.org/ adresini ziyaret edin

Makinenizde çalışan GPT'nin bir kopyasına sahip olduktan sonra Google paketinde temel istekler için Net:HTTP paketini kullanabilirsiniz. Aşağıdaki snippet'te, ihtiyaç duyulan içe aktarmaların nasıl yapılacağı hakkında bilgi edinmek için Rulo'nun etkileşimli kabuğundan yararlanabilirsiniz. Yaptığımız şey ise "net/http" paketi gerektirip en yüksek puan alan video feed'inin URL'sini YouTube'dan ayrıştırıp HTTP GET isteği gerçekleştirmektir.

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>

Bu istek, komut satırında büyük ölçüde XML çağrıştırmış olmalıdır. Tüm öğelerin bir <feed> öğesinin içinde bulunduğunu ve <input> öğeleri olarak adlandırıldığını fark etmiş olabilirsiniz. Henüz XML biçimlendirmesi konusunda endişelenmemize gerek yok. HTTP kullanarak temel bir Google Data API isteğinin nasıl yapılacağını açıklamak istedim. Gönderebileceğimiz ve gönderebileceğimiz bilgiler daha "komuta uygun" olduğundan API'leri şimdi değiştireceğiz ve E-Tablolar'a odaklanacağız.

Kimlik Doğrulama | Google Sheets API'yi Kullanma

Yine bir giriş öğeleri feed'i alarak başlayacağız. Kendi e-tablolarımızla çalışmayı planlıyoruz. Bunun için önce Google Hesapları hizmetiyle kimlik doğrulaması yapmamız gerekir.

GData Authentication ile ilgili belgelerden hatırladığınız gibi, Google'ın hizmetlerinde kimlik doğrulamanın iki yolu vardır. AuthSub web tabanlı uygulamalar içindir ve bir jeton değişimi işlemi içerir. AuthSub'ın gerçek avantajı, uygulamanızın kullanıcı kimlik bilgilerini depolamak zorunda olmamasıdır. ClientLogin "yüklü" uygulamalar içindir. ClientLogin işleminde, kullanıcı adı ve şifre, kullanmak istediğiniz hizmeti tanımlayan bir dizeyle birlikte Google hizmetlerine https üzerinden gönderilir. Google Sheets API hizmeti, wise dizesiyle tanımlanır.

Etkileşimli kabuğumuza dönecek olursak, Google'da kimlik doğrulaması yapalım. Kimlik doğrulama isteğimizi ve kimlik bilgilerinizi göndermek için https kullandığımızı unutmayın:

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 ]

Tamam'a dokunun. Kimliğinizi doğruladığımıza göre,

http://spreadsheets.google.com/feeds/spreadsheets/private/full

Bu, kimliği doğrulanmış bir istek olduğu için başlıklarımızı da aktarmak isteriz. Aslında, çeşitli feed'ler için birkaç istekte bulunacağımızdan bu işlevi get_feed olarak adlandıracağımız basit bir işleve de dönüştürebiliriz.

# 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> ...

Yine, XML'nin büyük bir kısmını, komut satırından şifre çözme konusunda endişelenmeniz gerekmediği için, yukarıda vurguladığımızı görüyoruz. Sitenizi daha kullanıcı dostu hale getirmek için XmlSimple kullanarak bunu bir veri yapısına ayrıştıralım:

# 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 ]

Çalışma sayfaları alma

Yukarıdaki çıktıda görebileceğiniz gibi, feed'im 6 e-tablo içeriyor. Bu makaleyi kısa tutmak için yukarıdaki XML çıkışının (ve diğer çoğu girişin) geri kalanını kestim. Bu e-tabloyu daha ayrıntılı incelemek için birkaç adım daha uygulamamız gerekiyor:

  1. E-tablo anahtarını edinme
  2. Çalışma sayfası feed'imizi almak için e-tablo anahtarını kullanın
  3. Kullanmak istediğimiz çalışma sayfasının kimliğini öğrenme
  4. Çalışma sayfasının gerçek içeriğine erişmek için hücrelerFeed'i veya listFeed'i isteyin

Bu çok fazla iş gibi gelebilir, ancak birkaç basit yöntem yazmamız durumunda her şeyin çok kolay olduğunu göstereceğim. hücrelerFeed'i ve listeFeed'i, bir çalışma sayfasının gerçek hücre içeriği için iki farklı temsildir. listFeed, bir bilgi satırının tamamını temsil eder ve yeni veri yayınlamak için önerilir. HücreFeed, hücreleri tek tek temsil eder ve ya tek tek hücre güncellemeleri ya da birçok hücredeki toplu güncellemeler (PUT kullanılarak) için kullanılır. Daha fazla ayrıntı için lütfen Google Sheets API'ye bakın.

Çalışma sayfası feed'ini almak için öncelikle e-tablo anahtarını (yukarıdaki XML çıkışında vurgulanmış olarak) almamız gerekir:

# 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 ]

Gördüğünüz gibi, listFeed ve hücrelerFeed'ine erişmek için kullanabileceğiniz bağlantıları (highlighted above) bulabiliriz. listFeed'i incelemeye başlamadan önce, ne aradığımızı bilmeniz için şu anda örnek e-tablomuzda hangi verilerin olduğunu hızlı bir şekilde açıklayacağım:

E-tablomuz çok basittir ve şu şekilde görünür:

languageweb sitesi
javahttp://java.com
phphttp://php.net

Bu veriler listFeed'de şu şekilde görünür:

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 ]

Gördüğünüz gibi, listFeed, her satır için bir giriş oluşturarak çalışma sayfanızın içeriğini döndürür. E-tablonun ilk satırında hücre başlıklarınızın bulunduğu varsayılır, ardından dinamik olarak bu satırdaki verilere dayalı XML başlıkları oluşturulur. Gerçek XML'e bakmak, bunu daha iyi açıklamanıza yardımcı olacaktır:

<?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>

Hızlı bir karşılaştırma yapmak için aynı bilgilerin hücrelerFeed'inde nasıl temsil edildiğine göz atalım:

# 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 ]

Burada görebileceğiniz gibi, her hücre için bir tane olmak üzere 6 giriş döndürülür. "Dil" kelimesini içeren A1 hücresinin değerinin yanı sıra diğer tüm sonuçları kestim. Yukarıda gösterilen düzenle bağlantısına da dikkat edin. Bu bağlantının sonunda bir sürüm dizesi (8srvb) bulunmaktadır. Bu makalenin sonunda yapacağımız gibi, hücre verilerini güncellerken sürüm dizesi önemlidir. Güncellemelerin üzerine yazılmamasını sağlar. Hücre verilerini güncellemek için PUT isteğinde bulunduğunuzda, istekte hücrenin en son sürüm dizesini eklemeniz gerekir. Her güncellemeden sonra yeni bir sürüm dizesi döndürülür.

Liste feed'inde içerik yayınlama

İçerik yayınlamak için ihtiyacımız olan ilk şey listFeed'in POST bağlantısıdır. Bu bağlantı, liste feed'i istendiğinde döndürülür. Bu URL, rel özelliğinin değeri olarak http://schemas.google.com/g/2005#post URL'sini içerir. Bu bağlantı öğesini ayrıştırıp href özelliğini çıkarmanız gerekir. İlk olarak, yayınlamayı kolaylaştırmak için küçük bir yöntem oluşturacağız:

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 durumu, gönderimizin başarılı olduğunu gösteriyor.

İçeriği güncellemek için hücrelerFeed'ini kullanma

Dokümanlarda, hücre feed'inin mevcut içeriklerde PUT isteklerini tercih ettiğini görüyoruz. Ancak, yukarıdaki hücrelerFeed'den aldığımız bilgiler yalnızca gerçek e-tablomuzda bulunan halihazırda bulunan veriler olduğundan, yeni bilgileri nasıl ekleyebiliriz? Yalnızca veri girmek istediğimiz her boş hücre için istekte bulunmamız gerekir. Aşağıdaki snippet'te, Python programlama diliyle ilgili bazı bilgiler eklemek istediğimiz boş R5C1 hücresinin (5. Satır, 1. Sütun) nasıl alınacağı gösterilmektedir.

Orijinal değişkenimiz cellfeed_uri, hücre feed'inin kendisi için yalnızca URI'yı içeriyordu. Şimdi, düzenlemek istediğimiz hücreyi eklemek ve düzenleme yapmak için ilgili hücrenin sürüm dizesini almak istiyoruz:

# 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>"

Yukarıdaki kod listesinde görebileceğiniz gibi, sürüm dizesi 47pc şeklindedir. (Sağa doğru en sonuna kaydırmanız gerekebilir.) İşinizi kolaylaştırmak için ilgilendiğimiz herhangi bir hücrenin sürüm dizesini bize sağlayan bir kolaylık yöntemi oluşturalım:

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

Biz bunu yaparken, PUT isteğini yerine getirmek için bir yöntem de yazabiliriz veya daha da iyisi, toplu güncellemenin tamamını gerçekleştirmek için bir yöntem yazabiliriz. İşlevimiz, aşağıdaki değişkenleri içeren bir karma oluşturma işlemi alacaktır:

  • :batch_id - Toplu isteğin her bir parçası için benzersiz bir tanımlayıcı.
  • :cell_id - A1 hücresinin R1C1 olarak temsil edileceği, R#C# biçiminde güncellenecek hücrenin kimliği.
  • :data - Eklemek istediğimiz veriler.

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 ]

Gördüğünüz gibi, toplu istek aldığımızda 200 OK yanıt kodunu aldık. Yanıt XML'ini ayrıştırdığımızda, response_data dizimizde ayarladığımız her :batch_id için ayrı bir ileti döndürüldüğünü görebiliriz. Toplu işleme hakkında daha fazla bilgi için lütfen GData'da Toplu İşleme belgelerini inceleyin.

Sonuç

Gördüğünüz gibi, Roku'nun etkileşimli kabuğunu kullanarak Google Veri API'larıyla denemeler yapmak çok kolay. Hem listFeed'i hem de hücrelerFeed'i kullanarak e-tablolarımıza ve çalışma sayfalarımıza erişebildik. Ayrıca bir POST isteği kullanarak bazı yeni veriler ekledik ve ardından yalnızca yaklaşık 120 kod satırıyla toplu güncelleme yapmak için yöntemler yazdık. Bu noktada, bu basit yöntemlerden bazılarını sınıflara eklemek ve kendinizi yeniden kullanılabilir bir çerçeve haline getirmek çok zor olmamalıdır.

En sevdiğiniz Google Data API ile bu araçların kullanımı hakkında sorularınız varsa lütfen tartışma gruplarında bize katılın.

Yukarıda ayrıntılı olarak verilen kod örneklerini içeren bir sınıf dosyasına http://code.google.com/p/google-data-samples-ruby adresinden ulaşabilirsiniz.

Bu makale hakkında bilgi edinin.