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