Работа с удаленным содержанием

Этот документ описывает, как получать и манипулировать удаленными текстовыми данными (обычно HTML), данными XML и JSON и данными RSS/Atom-фидов.

Содержание

  1. Введение
  2. Работа с различными типами содержания
    1. Работа с текстом
    2. Работа с XML
    3. Работа с фидами
    4. Работа с JSON
  3. Настройка типа авторизации
  4. Методы
    1. GET
    2. POST
  5. Обновление кэша

Введение

Одна из самых интересных функций гаджетов – возможность комбинировать информацию из разных источников новыми способами или предоставлять особые способы взаимодействия с существующей информацией. API гаджетов позволяет гаджету получать и обрабатывать удаленное содержание с разных веб-серверов и веб-страниц.

API гаджетов обеспечивает функцию makeRequest(url, callback, opt_params) для получения и обработки удаленного содержания в Интернете. Она принимает следующие аргументы.

  • String url – URL, где расположено содержимое
  • Function callback – функция, которую следует вызвать с данными из URL после создания выборки
  • Map.<gadgets.io.RequestParameters, Object> opt_params – дополнительные параметры для прохождения запроса.

Аргумент opt_params позволяет указывать следующее.

  • Тип содержания запроса (TEXT, XML, FEED и JSON)
  • Тип метода запроса (POST или GET)
  • Заголовки, которые нужно включить в запрос
  • Тип авторизации (NONE, SIGNED и OAUTH )

Примечание. Нельзя использовать makeRequest() с гаджетами type="url".

Независимо от получаемого типа данных, вызовы к makeRequest() имеют общие характеристики:

  • Их первый параметр – URL, использующийся для получения удаленного содержания.
  • Второй параметр – callback-функция, используемая для обработки возвращенных данных.
  • Они асинхронные, то есть вся обработка должна происходить в callback-функции. Callback – это функция, передаваемая как параметр (в виде ссылки на функцию) другой функции. Callback-функции позволяют сторонним разработчикам "зацепиться" за работающую инфраструктуру и выполнить какую-либо обработку.
  • У них нет возвращаемых значений, потому что они возвращают сразу же, а связанные с ними callback-функции вызываются при возврате ответа.

Например, посмотрим на этот фрагмент кода, получающий удаленное содержание в виде текста. Этот код получает текст HTML с веб-страницы google.com и отображает первые 400 символов:

function getHtml() {    
  var params = {};  
  params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT;  
  var url = "http://www.google.com";  
  gadgets.io.makeRequest(url, response, params);
};
function response(obj) {  
  //obj.text contains the text of the page that was requested  
  var str = obj.text;
  var html =  str.substr(0,400);  
  document.getElementById('content_div').innerHTML = html;
};
gadgets.util.registerOnLoadHandler(getHtml);

Этот пример демонстрирует основные принципы работы makeRequest().

  1. При вызове makeRequest(), API гаджетов выполняет асинхронный запрос HTTP GET на URL, переданный в функции (в этом примере URL – http://www.google.com).
  2. makeRequest()сразу делает возврат и после этого, когда завершается получение, вызывает callback-функцию (в этом примере response()). Это значит, что весь зависимый код надо разместить внутри callback-функции или внутри функций, вызываемых callback-функцией.
  3. makeRequest() возвращает объект JavaScript со следующей структурой:
{
  data : <parsed data, if applicable>,
  errors : <any errors that occurred>,
  text : <raw text of the response>  
}  

Этот объект предоставляется как единственный аргумент callback-функции. Callback-функция выполняет некоторые операции на возвращенных данных. Обычно она извлекает части данных, комбинирует их с разметкой HTML и выводит получающийся HTML в гаджете.

Работа с различными типами содержания

По умолчанию содержание удаленного сайта возвращается как текст. Для установки одного из нижеследующих типов возвращаемого содержания можно использовать поле opt_params.

  • TEXTgadgets.io.ContentType.TEXT
  • DOMgadgets.io.ContentType.DOM
  • FEEDgadgets.io.ContentType.FEED
  • JSONgadgets.io.ContentType.JSON

Работа с текстом

Этот пример получает данные из файла CSV (значения, разделенные запятыми) и заполняет ими список личных знакомых. Он показывает, как установить тип получаемого содержания в дополнительных параметрах. В callback-функции response(obj) текстовое значение извлекается из obj с помощью obj.text:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="Fetch Text Example"/>
  <Content type="html">
  <![CDATA[
  <div id="content_div"></div>
  <script type="text/javascript">

  // This example fetches data from a CSV file containing contact information. In the CSV file, 
  // each record consists of a name, email address, and phone number.
  function getContacts() {
    var params = {};  
    params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT;  
    var url = "http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/Contacts.csv";
    gadgets.io.makeRequest(url, response, params);
  };
  // Callback function to process the response
  function response(obj) {               
    var responseText = obj.text;  
    // Set CSS for div.
    var html = "<div style='padding: 5px;background-color: #FFFFBF;font-family:Arial, Helvetica;" 
    + "text-align:left;font-size:90%'>"; 

    // Use the split function to extract substrings separated by comma 
    // delimiters.
    var contacts = responseText.split(",");
    // Process array of extracted substrings.
    for (var i = 0; i < contacts.length ; i++) {
      // Append substrings to html.
      html += contacts[i]; 
      html += " ";

      // Each record consists of 3 components: name, email, and
      // phone number. The gadget displays each record on a single
      // line:
      //
      // Mickey Mouse mickey@disneyland.com 1-800-MYMOUSE
      //
      // Therefore, insert a line break after each (name,email,phone)
      // triplet (i.e., whenever (i+1) is a multiple of 3).
      if((i+1)%3 ==0) { 
        html += "<br>";
      }
    }
    html += "</div>";
    // Output html in div.
    document.getElementById('content_div').innerHTML = html;
  }
  gadgets.util.registerOnLoadHandler(getContacts);

 </script>
  ]]>
  </Content>
</Module>

Работа с XML

Модель объекта документа (DOM) – это API для переходов по документам в HTML и XML. Для получения документа XML как объекта DOM можно использовать makeRequest() . Получив объект, вы можете манипулировать с ним обычными функциями JavaScript DOM. Обычно это значит извлечь нужные данные из файла XML, объединить их с разметкой HTML и CSS и вывести получающийся HTML в своем гаджете.

В DOM содержимое из Интернета преобразуется в дерево узлов. Например, посмотрите на этот фрагмент HTML:

<a href="http://www.google.com/">Google's <b>fast</b> home page.</a>

Этот фрагмент иллюстрирует основные типы узлов, о которых говорится в этом разделе.

  • Узлы элементов. Узлы элементов в этом фрагменте – “a” и “b”. Узлы элементов – это строительные блоки, определяющие структуру документа.
  • Узлы текста. Узлы текста в этом фрагменте – ‘Google’s’, ‘fast’ и ‘home page.’ Узлы текста всегда содержатся в узлах элементов. Это дочерние узлы содержащего их узла элементов.
  • Узлы атрибутов. Этот фрагмент имеет один узел атрибутов: href=’http://www.google.com’. Узел атрибутов обеспечивает дополнительную информацию о содержащем его узле элементов. Атрибуты, однако, не считаются дочерними узлами содержащего их элемента. Это влияет на работу с ними. Более подробное обсуждение этого вопроса см. в разделе Работа с различными типами узлов.

Вот структура DOM для фрагмента HTML:

Дерево DOM

Для доступа к данным в объекте DOM нужно "пройти дерево", используя функции DOM для перехода между материнскими и дочерними узлами и получения нужных данных.

Пример

Следующий файл XML содержит данные серии предметов для завтрака. Верхний материнский узел – menu, у него есть несколько дочерних узлов food. Узел menu содержит также узел атрибутов: title="Breakfast Menu". Каждый узел food содержит дочерние узлыname, price, description и calories.

Узлы name, price и calories содержат дочерние узлы "text". Узлы description содержат дочерний узел CDATA. CDATA – это определенный тип узла. Разделы CDATA используются для перевода фрагментов текста, содержащих символы, которые в противном случае считались бы разметкой, например, угловые скобки. Единственный ограничитель, узнаваемый в разделе CDATA – это строка “]]>”, которая оканчивает раздел CDATA.

<?xml version="1.0" encoding="UTF-8" ?>
<menu title="Breakfast Menu">
  <food>
     <name>Early Bird Breakfast</name> 
     <price>$3.95</price> 
     <description><![CDATA[<div style="color:purple; padding-left:25px;">Two eggs any style with your choice of bacon 
or sausage, toast or English muffin.</div>]]></description> 
     <calories>450</calories> 
  </food>

  <food>
     <name>Chocolate Chip Belgian Waffles</name> 
     <price>$7.95</price> 
     <description><![CDATA[<div style="color:purple; padding-left:25px;">Chocolate chip Belgian waffles covered with 
chocolate syrup and whipped cream.</div>]]></description> 
     <calories>900</calories> 
 </food>

     …
</menu>

Следующий пример гаджета использует этот файл XML как источник данных. Он отображает меню завтрака и позволяет пользователям установить ограничение по калориям. Он отображает красным калории сверх указанного предела. Пользователи могут также выбирать, отображать ли описания для каждого из элементов завтрака.

Следующий код показывает, как проходить дерево DOM для извлечения данных из различных типов узлов и как комбинировать данные с разметкой HTML и CSS для отображения в гаджете меню завтрака.

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="Fetch XML" scrolling="true"/>
  <UserPref 
    name="mycalories" 
    display_name="Calorie limit" 
    default_value="800"/>
  <UserPref 
    name="mychoice" 
    display_name="Show Descriptions" 
    datatype="bool" 
    default_value="false"/>
  <Content type="html">
  <![CDATA[
    <div id="content_div"></div>
    <script type="text/javascript">
      // get prefs
      var prefs = new gadgets.Prefs();
      // Calorie limit set by user
      var calorieLimit = prefs.getString("mycalories");
      // Indicates whether to show descriptions in the breakfast menu    
      var description = prefs.getBool("mychoice");

      function makeDOMRequest() {    
        var params = {};  
        params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.DOM;  
        var url = "http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/breakfast-data.xml";  
        gadgets.io.makeRequest(url, response, params);
      };
      function response(obj) { 
        // Start building HTML string that will be displayed in <div>.           
        // Set the style for the <div>.        
        var html = "<div style='padding: 5px;background-color: #ccf;font-family:Arial, Helvetica;" 
          + "text-align:left;font-size:90%'>";   
        // Set style for title.
        html +="<div style='text-align:center; font-size: 120%; color: yellow; " 
          + "font-weight: 700;'>"; 
        // obj.data contains a Document DOM element corresponding to the
        // page that was requested
        var domdata = obj.data;

        // Display menu title. Use getElementsByTagName() to retrieve the <menu> element.
        // Since there is only one menu element in the file,
        // you can get to it by accessing the item at index "0". 
        // You can then use getAttribute to get the text associated with the
        // menu "title" attribute.
        var title = domdata.getElementsByTagName("menu").item(0).getAttribute("title");

        // Alternatively, you could retrieve the title by getting the menu element node
        // and calling the "attributes" function on it. This returns an array
        // of the element node's attributes. In this case, there is only one
        // attribute (title), so you could display the value for the attribute at
        // index 0. For example:
        // 
        // var title = domdata.getElementsByTagName("menu").item(0).attributes.item(0).nodeValue; 

        html += title + "</div><br>"; 
        // Get a list of the <food> element nodes in the file
        var itemList = domdata.getElementsByTagName("food");
 
        // Loop through all <food> nodes
        for (var i = 0; i < itemList.length ; i++) { 
        // For each <food> node, get child nodes.
        var nodeList = itemList.item(i).childNodes;

        // Loop through child nodes. Extract data from the text nodes that are
        // the children of the associated name, price, and calories element nodes.
        for (var j = 0; j < nodeList.length ; j++) {
          var node = nodeList.item(j);
          if (node.nodeName == "name") 
          {
            var name = node.firstChild.nodeValue;
          }
          if (node.nodeName == "price") 
          {
            var price = node.firstChild.nodeValue;
          }
          if (node.nodeName == "calories") 
          {
            var calories = node.firstChild.nodeValue; 
          }
          // If the user chose to display descriptions and
          // the child node is "#cdata-section", grab the 
          // contents of the description CDATA for display.
          if (node.nodeName == "description" && description==true)
          {
            if (node.firstChild.nodeName == "#cdata-section") 
              var data = node.firstChild.nodeValue;
          }
        } 
        // Append extracted data to the HTML string.
        html += "<i><b>";
        html += name;
        html += "</b></i><br>";
        html += "&emsp;"; 
        html += price;
        html += " - ";
        // If "calories" is greater than the user-specified calorie limit,
        // display it in red.
        if(calories > calorieLimit) {
          html += "<font color=#ff0000>";
          html += calories + " calories";
          html += " </font>"; 
        }
        else
          html += calories + " calories";
        html += "<br>";
        // If user has chosen to display descriptions
        if (description==true) 
        {
          html += "<i>" + data + "</i><br>";
        } 
      } 
      // Close up div
      html += "</div>";
      document.getElementById('content_div').innerHTML = html;
    };
    gadgets.util.registerOnLoadHandler(makeDOMRequest);
    </script>
  ]]>
  </Content>
</Module>

Этот пример кода показывает четыре основных функции, используемые для взаимодействия с данными DOM:

  • getElementsByTagName(tagname)— для документа DOM, возвращает массив узлов элементов, чьи названия соответствуют tagname. Можно получить все узлы элементов файла, используя обобщающий символ (*), например: response.getElementsByTagName("*").
  • getElementById(id)— для документа DOM, получает один узел по идентификатору.
  • getAttribute(attrib)— для узла элементов, возвращает атрибутattrib. Например: response.getElementsByTagName("menu").item(0).getAttribute("title").
  • attributes – для узла элементов, возвращает массив атрибутов узла.

Этот пример показывает только несколько функций перехода по дереву DOM. Можно еще попробовать lastChild, nextSibling, previousSibling и parentNode.

Работа с различными типами узлов

Ключ к эффективной работе с DOM – понимание различий (иногда очень небольших) между типами узлов.

Тип узла Описание Возвращаемые значения Особенности
element Структурный строительный блок документа, например: <p> , <b> или<calories>. nodeName: текст, содержащийся в угловых скобках. Например: nodeName <menu>“menu”.

nodeType: 1

nodeValue : null
Элемент имеет nodeValue null. Для получения значения узла текста или атрибутов, связанного с элементом, нужно перейти к этим узлам. Например: element.firstChild.nodeValue для текста и element.getAttribute(attrib) для атрибутов.
text Текст. Узел текста всегда содержится в элементе. Он – дочерний для элемента. nodeName: #text

nodeType: 3

nodeValue: Текст, содержащийся в узле.
Некоторые браузеры обрабатывают все пустое пространство в документе как текстовые узлы, поэтому вы получаете "пустые" текстовые узлы в объекте DOM. Это может вызывать неожиданные результаты при прохождении дерева. Решение может быть простым, например, отфильтровать текстовые узлы, содержащие только символ перевода строки, а можно обеспечить более надежную обработку. Подробное обсуждение этой темы см. в разделе Пустое пространство в DOM
attribute Пара ключ-значение, обеспечивающая дополнительную информацию об узле элементов (например, title=”my document”). Атрибут содержится в узле элементов, но является дочерним по отношению к нему. nodeName: Левое значение в паре атрибута. Если атрибут – title=”my document”, nodeName будет title.

nodeType: 2

nodeValue: Правое значение в паре атрибута (в этом примере “my document”).
Атрибуты – это узлы, они содержатся внутри узлов элементов, но, тем не менее, не являются дочерними по отношению к элементу. Они наследуют от интерфейса Node, но DOM не считает их частью дерева DOM. Это значит, что на узлах атрибутов можно использовать многие функции узлов (например nodeName, nodeValue и nodeType), но к ним нельзя получить доступ с помощью функций прохода по дереву DOM. Для доступа к атрибутам используются функции attributes и getAttribute(attrib).
CDATA Раздел, в котором содержание не интерпретируется. разделы CDATA используются для перевода фрагментов текста, содержащих символы, которые в противном случае считались бы разметкой. Единственный ограничитель, узнаваемый в разделе CDATA – это строка "]]>", которая оканчивает раздел CDATA. nodeName: #cdata-section

nodeType: 4

nodeValue: Текст и разметка в ограничителях CDATA.

Текст в разделе CDATA имеет собственную разметку. Это может иметь значение для встраивания в гаджет.
Другие ресурсы

Работа с фидами

К своей странице iGoogle можно добавить фид, введя URL в форму Добавить URL в каталоге содержания. Она использует встроенную в API гаждетов поддержку фидов и создает гаджет для фида, добавляя его к iGoogle. Это легко использовать, но это не дает возможности как-либо настраивать содержимое или отображение. Это также невозможно использовать с другими контейнерами.

Для более сложной обработки каналов можно использовать метод makeRequest() и указывать тип содержания FEED. Запросы фидов пытаются анализировать фид ATOM или RSS XML и возвращают ответ как объект, кодированный в JSON.

С типом содержания FEED можно определить следующие параметры.

Параметр Тип данных Описание
gadgets.io.RequestParameters.NUM_ENTRIES Число, дополнительный Количество записей фида, подлежащих извлечению. Принятый диапазон – от 1 до 100. Значение по умолчанию – 3.
gadgets.io.RequestParameters.GET_SUMMARIES Логическое значение, дополнительное Параметр, определяющий, нужно ли извлекать краткую сводку полного текста из записи фида. Значение по умолчанию "false". Параметру необходимо присваивать значение "true" только в том случае, если планируется использовать эти данные. Сводки могут оказаться довольно большими, и их не стоит передавать, если в этом нет необходимости.

Ниже приведены поля объекта фида JSON.

Поле Описание
ErrorMsg Если значение определено, оно описывает зарегистрированную ошибку.
URL URL RSS- или Atom-фида.
Title Название фида.
Description Строка тега или описания фида.
Link Как правило, это URL главной страницы фида.
Author Автор фида.
Entry Массив записей фида. В запись включены следующие поля.
  • Title. Название записи фида.
  • Link. URL записи фида.
  • Summary. Содержание или сводка записи фида.
  • Date. Отметка времени для записи в секундах (с 1 января 1970 года). Для преобразования в милисекунды, которые нужны для запуска объекта JavaScript Date с правильной датой, умножьте на 1000. Ниже в качестве примера приводится код образца гаджета.

Например, посмотрим на такой RSS-фид:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
<rss version="2.0">
<channel>
<title>Code Examples for makeRequest()</title>
<link>http://code.google.com/apis/gadgets/docs/remote-content.html</link>
<description>This feed lists code examples for the gadgets.* makeRequest() function.</description>
<language>en</language>
<item>
<title>Fetch Text Example</title>
<link>http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/fetch-csv.xml</link>
<description>This example illustrates how to use makeRequest() with text content.</description>
<author>Google</author>
<pubDate>Sat, 09 Aug 2008 11:46:09 UT</pubDate> </item>
<item>
<title>Fetch XML Example</title>
<link>http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/fetch-XML.xml</link>
<description>This section describes how to use makeRequest() with XML content.</description>
<author>Google</author>
<pubDate>Sat, 09 Aug 2008 11:46:09 UT</pubDate>
</item>
<item>
<title>Feed Fetch Example</title>
<link>http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/feed-fetch.xml</link>
<description>This example illustrates how to use makeRequest() with Feed content.</description>
<author>Google</author>
<pubDate>Sat, 09 Aug 2008 10:33:09 UT</pubDate>
</item>
<item>
<title>Fetch JSON Example</title>
<link>http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/fetch-json.xml</link>
<description>This example illustrates how to use makeRequest() with JSON content.</description>
<author>Google</author>
<pubDate>Sat, 09 Aug 2008 03:55:28 UT</pubDate> </item>
</channel>
</rss>

Если получить этот фид с типом содержания FEED, возвращаемое значение будет кодировано как строка JSON следующим образом:

{"Entry":
  [
    {
      "Link":"http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/fetch-csv.xml",
      "Date":1218282369000,
      "Title":"Fetch Text Example",
      "Summary":"This example illustrates how to use makeRequest() with text content."
    },
    {
      "Link":"http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/fetch-XML.xml",
      "Date":1218282369000,
      "Title":"Fetch XML Example",
      "Summary":"This section describes how to use makeRequest() with XML content."
    },
    {
      "Link":"http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/feed-fetch.xml",
      "Date":1218277989000,
      "Title":"Feed Fetch Example",
      "Summary":"This example illustrates how to use makeRequest() with Feed content."
    },
    {
      "Link":"http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/fetch-json.xml",
      "Date":1218254128000,
      "Title":"Fetch JSON Example",
      "Summary":"This example illustrates how to use makeRequest() with JSON content."
    }
  ],
  "Description":"This feed lists code examples for the gadgets.* makeRequest() function.",
  "Link":"http://code.google.com/apis/gadgets/docs/remote-content.html",
  "Author":"Google",
  "URL":"http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/sample-gadgets-feed.xml",
  "Title":"Code Examples for makeRequest()"
}
    

Следующий пример показывает, как использовать makeRequest() для получения фида и отображения частей его данных в гаджете. Вот гаджет. Он получает фид, содержащий записи с форума разработчиков гаджетов. Он позволяет пользователям определять следующее.

  • Число показываемых записей.
  • Должен ли гаджет отображать даты для записей
  • Должен ли гаджет отображать сводки для записей

Вот код этого примера:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="Fetch Feed Example" 
    title_url="http://groups.google.com/group/Google-Gadgets-API" 
    scrolling="true">
  </ModulePrefs>
  <UserPref name="show_date" display_name="Show Dates?" datatype="bool" default_value="false"/>
  <UserPref name="num_entries" display_name="Number of Entries:" default_value="5"/>
  <UserPref name="show_summ" display_name="Show Summaries?" datatype="bool" default_value="false"/>
  <Content type="html">
  <![CDATA[
  <style> #content_div { font-size: 80%;  margin: 5px; background-color: #FFFFBF;} </style>
  <div id="content_div"></div>
  <script type="text/javascript">

  // Get userprefs
  var prefs = new gadgets.Prefs();
  var showdate = prefs.getBool("show_date");
  var entries = prefs.getInt("num_entries");
  var summaries = prefs.getBool("show_summ");

  function getFeed() {  
    var params = {};  
    params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.FEED;  
    params[gadgets.io.RequestParameters.NUM_ENTRIES] = new Number(entries);  
    params[gadgets.io.RequestParameters.GET_SUMMARIES] = summaries; 
    var url = "http://groups.google.com/group/Google-Gadgets-API/feed/rss_v2_0_msgs.xml";  
    gadgets.io.makeRequest(url, response, params);
  };

  function response(obj) { 
    // obj.data contains the feed data
    var feed = obj.data;
    var html = "";

    // Display the feed title and description
    html += "<div><b>" + feed.Title + "</b></div>";
    html += "<div>" + feed.Description + "</div><br>";
      
    // Access the data for a given entry
    if (feed.Entry) {
      for (var i = 0; i < feed.Entry.length; i++) {
        html += "<div>"
          + "<a target='_blank' href='" + feed.Entry[i].Link + "'>"
          + feed.Entry[i].Title
          + "</a> ";
        if (showdate==true)
        { 
          // The feed entry Date field contains the timestamp in seconds
          // since Jan. 1, 1970. To convert it to the milliseconds needed
          // to initialize the JavaScript Date object with the correct date, 
          // multiply by 1000.
          var milliseconds = (feed.Entry[i].Date) * 1000; 
          var date = new Date(milliseconds); 
          html += date.toLocaleDateString();
          html += " ";
          html += date.toLocaleTimeString(); 
        }
        if (summaries==true) { 
          html += "<br><i>" + feed.Entry[i].Summary + "</i>";
        }
        html += "</div>";
      }
    }        
    document.getElementById('content_div').innerHTML = html;
  };
  gadgets.util.registerOnLoadHandler(getFeed);
  </script>
  ]]>
  </Content>
</Module>

Работа с JSON

JSON (JavaScript Object Notation) – это формат обмена данными, позволяющий кодировать определенные типы объектов (массивы и наборы пар ключ-значение) как строки, которые легко передавать. Тип содержимого JSON можно использовать для получения содержимого в кодировке JSON как объекта JavaScript.

Приложение ниже получает содержимое из текстового файла, содержащего следующую строку в кодировке JSON:

{"Name" : "Rowan", "Breed" : "Labrador Retriever", "Hobbies" : ["fetching", "swimming", "tugging", "eating"]}

При получении содержимого из текстового файла с этой строкой, возвращаемое значение – объект JavaScript, содержащий пары ключ-значение (то есть ассоциативная матрица). Этот пример получает объект и затем выводит содержащиеся в нем пары ключ-значение. Если в массиве есть значение (это указывается квадратными скобками []), он превращает содержание массива в список с точками:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="Fetch JSON Example"/>
  <Content type="html">
  <![CDATA[
    <div id="content_div"></div>
    <script type="text/javascript">

    function makeJSONRequest() {    
      var params = {};
      params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON;
      // This URL returns a JSON-encoded string that represents a JavaScript object
      var url = "http://gadget-doc-examples.googlecode.com/svn/trunk/opensocial-gadgets/json-data.txt";
      gadgets.io.makeRequest(url, response, params);
    };

    function response(obj) { 
      var jsondata = obj.data;
      var html = "";
      // Process returned JS object as an associative array
      for (var key in jsondata) {
        var value = jsondata[key];
        html += key + ": ";
        // If 'value' is an array, render its contents as a bulleted list
        if (value instanceof Array)
        {
          html += "<br /><ul>";
          for (var i = 0; i < value.length ; i++)
          {
            html += "<li>"+ jsondata.Hobbies[i] + "</li>";
          }
          html+= "</ul>";
        }  
        // If 'value' isn't an array, just write it out as a string
        else {        
          html += value + "<br />";
        }      
      }               
      document.getElementById('content_div').innerHTML = html;
     };
     gadgets.util.registerOnLoadHandler(makeJSONRequest);
     </script>
  ]]>
  </Content>
</Module>

Вот вывод гаджета:

Имя: Rowan
Порода: Labrador Retriever
Хобби:

  • fetching
  • swimming
  • tugging
  • eating

Подробнее о JSON

API гаджетов предоставляет метод gadgets.json.stringify(), который кодирует объекты в строки JSON, и метод gadgets.json.parse(), превращающий строку JSON в объект. OpenSocial автоматически выполняет перевод с HTML всех возвращенных данных, включая данные приложения, поэтому перед анализом необходимо сделать обратный переход для строчных объектов JSON в хранилище данных приложения, например gadgets.util.unescapeString(jsondata).

Этот пример создает массив JavaScript, кодирует его как строку JSON и превращает строку JSON снова в объект Array:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="JSON Example" />
  <Content type="html">
  <![CDATA[
     <div id="content_div"></div>
     <script type="text/javascript">
     var html = "";
     // Create Array object
     var myfriends = new Array();
     myfriends[0] = "Touki";
     myfriends[1] = "Rowan";
     myfriends[2] = "Trevor";

     // Encode array as JSON string
     var jsonString = toJSON(myfriends);
     html += "The JSON string is " + jsonString + "<br />";
     html += "The type of jsonString is " + typeof(jsonString) + "<br />";

     // Convert JSON string back to an object
     var arr_obj = toObject(jsonString);
     html += "The type of arr_obj is " + typeof(arr_obj);
     document.getElementById('content_div').innerHTML = html;

     // Encode object as JSON string
     function toJSON(obj) { 
       return gadgets.json.stringify(obj); 
     }

     // Convert JSON string into an object
     function toObject(str) {
       return gadgets.json.parse(str);
    }
    </script>
  ]]>
  </Content>
</Module>

Результат этого гаджета такой:

The JSON string is Touki","Rowan","Trevor
The type of jsonString is string
The type of arr_obj is object

Настройка типа авторизации

API гаджетов поддерживает следующие типы авторизации.

  • gadgets.io.AuthorizationType.OAUTH (контейнер использует протокол OAuth)
  • gadgets.io.AuthorizationType.SIGNED (запрос подписан контейнером).
  • gadgets.io.AuthorizationType.NONE (по умолчанию).

Использование этих методов зависит от контейнера. Вот один пример использования типа авторизации с подписью, который применяется в Orkut. Обсуждение использования OAuth в гаджетах можно найти в разделе Создание гаджетов OAuth.

Методы

makeRequest() позволяет выбирать методы HTTP GET или POST.

GET

Обычно метод GET используется для получения информации с веб-сайта. Для makeRequest() GET – режим по умолчанию, но можно также явно сделать запрос GET следующим образом:

function makeGETRequest(url) {
   var params = {};
   params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;
   gadgets.io.makeRequest(url, response, params); 
};
function response(obj) {
   alert(obj.text); 
};
makeGETRequest("http://example.com"); 

Для передачи параметров на свой сервер в запросе GET просто добавьте их к строке запроса при выполнении запроса:

makeGETRequest("http://example.com?param1=12345&param2=hello"); 

POST

Запросы POST обычно используются для передачи данных на сервер с целью изменить или удалить записанные данные. С помощью запроса POST можно передавать больше данных, чем с помощью запроса GET.

Запрос POST можно выполнить с помощью следующего кода:

function makePOSTRequest(url, postdata) {
   var params = {};
   postdata = gadgets.io.encodeValues(postdata);
   params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
   params[gadgets.io.RequestParameters.POST_DATA]= postdata;
   gadgets.io.makeRequest(url, response, params); 
};
function response(obj) {
   output(obj.text); 
};
var data = {   data1 : "test",   data2 : 123456 }; 
makePOSTRequest("http://example.com", data); 

Кроме указания метода (METHOD) в поле opt_params для этого запроса вы можете указать параметр для ключа gadgets.io.RequestParameters.POST_DATA. Кодированием по умолчанию для POST является application/x-www-form-urlencoded, из чего следует, что значением параметра POST_DATA будет серия пар ключ-значение, закодированных URL и объединенных амперсандами (&). Для упрощения преобразования объектов данных в этот формат существует функция gadgets.io.encodeValues. encodeValues принимает объект JavaScript и возвращает закодированную строку, подходящую для параметра POST_DATA.

Например, команда:

var data = {   data1 : "test",   data2 : 123456 };  gadgets.io.encodeValues(data); 

вызывает строку:

data1=test&data2=123456 

Такая строка может быть использована напрямую как значение для gadgets.io.RequestParameters.POST_DATA

Обновление кэша

Если вы используете makeRequest() для получения содержания, обновляемого чаще раза в час, например, данные фида, вы можете получить не самый свежий вариант. Это связано с тем, что результаты кэшируются для ускорения работы гаджета. Если вы хотите, чтобы гаджет точно имел самые свежие данные, можно использовать параметр refreshInterval для обхода кэша и обязательного обновления в пределах указываемого интервала. Другими словами, кэш обновляется каждые Х секунд, где X = refreshInterval.

Вызовы к makeRequest кэшируются по умолчанию. В примере ниже функция оболочки берет те же параметры, что и вызов makeRequest, но принимает еще параметр под названием refreshInterval, позволяющий задавать длительность кэширования.

function makeCachedRequest(url, callback, params, refreshInterval) {
  var ts = new Date().getTime();
  var sep = "?";
  if (refreshInterval && refreshInterval > 0) {
    ts = Math.floor(ts / (refreshInterval * 1000));
  }
  if (url.indexOf("?") > -1) {
    sep = "&";
  }
  url = [ url, sep, "nocache=", ts ].join("");
  gadgets.io.makeRequest(url, response, params);
}

Кэширование – полезная вещь, поэтому не следует обновлять кэш слишком часто. Это может снизить производительность. Кэширование ускоряет получение данных. Оно также уменьшает нагрузку на сторонние серверы с удаленным содержимым. Следует стараться не отключать кэш совсем (что можно сделать, использовав refreshInterval: 0). Если гаджет получает миллионы просмотров страниц в день, отправляя на серверы миллионы запросов, отключение кэша не только понизит его производительность, но и может перегрузить серверы, обеспечивающие гаджет данными.

Так как по умолчанию содержание обновляется каждый час, есть смысл указывать только интервал меньше часа. Рекомендованный интервал refreshInterval – от 60 до 3600.

В начало