Uso de contenido remoto

En este documento se describe cómo extraer y manipular datos de feeds remotos textuales (normalmente HTML), XML, JSON y RSS/Atom.

Contenido

  1. Introducción
  2. Uso de diferentes tipos de contenido
    1. Uso de texto
    2. Uso de XML
    3. Uso de feeds
    4. Uso de JSON
  3. Establecimiento de un tipo de autorización
  4. Métodos
    1. GET
    2. POST
  5. Actualización de la memoria caché

Introducción

Una de las novedades más interesantes disponibles para los gadgets son las nuevas formas de combinar información de varias fuentes diferentes o de interactuar con la información existente. El API de gadgets permitirá a tu gadget extraer de forma remota contenido de otros servidores y páginas web y trabajar con él.

El API de gadgets proporciona la función makeRequest(url, callback, opt_params) para recuperar y trabajar con contenido web remoto. Este método utiliza los siguientes argumentos:

  • String url - la URL donde se encuentra el contenido.
  • Function callback - la función que se va a ejecutar con los datos de la URL una vez extraída.
  • Map.<gadgets.io.RequestParameters, Object> opt_params - parámetros adicionales que se deben transmitir a la solicitud.

El argumento opt_params permite especificar lo siguiente:

  • El tipo de contenido de la solicitud (TEXT, XML, FEED y JSON)
  • El tipo de método de la solicitud (POST o GET)
  • Cualquier encabezado que quieras incluir en la solicitud
  • El tipo de autorización (NONE, SIGNED y OAUTH )

Nota: no se puede utilizar makeRequest() con gadgets type="url".

Independientemente del tipo de datos que estén extrayendo, las llamadas a makeRequest() comparten las mismas características:

  • Su primer parámetro es una URL que permite extraer el contenido remoto.
  • Su segundo parámetro es una función de devolución de llamada que permite procesar los datos obtenidos.
  • Son asíncronos, lo que significa que todos los procesos deben realizarse dentro de la función de devolución de llamada. Una devolución de llamada es una función transmitida como un parámetro (en forma de una referencia de función) a otra función. Las devoluciones de llamada permiten a los desarrolladores conectarse a un framework de ejecución para realizar algunos procesos.
  • No tienen valores de retorno porque las devoluciones se realizan de forma inmediata y sus funciones de devolución de llamada asociadas se ejecutan siempre que se devuelve la respuesta.

Toma como ejemplo el siguiente fragmento de código, que extrae contenido remoto en forma de texto. Este código extrae el texto HTML de la página web google.com y muestra los primeros 400 caracteres:

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);

Este ejemplo ilustra los principios básicos del funcionamiento del parámetro makeRequest():

  1. Cuando se ejecuta makeRequest(), el API de gadgets realiza una solicitud GET HTTP asíncrona a la URL incluida en la función (en este ejemplo, la URL es http://www.google.com).
  2. makeRequest() regresa inmediatamente y más tarde ejecuta la función de devolución de llamada (en este ejemplo response()), cuando finaliza la extracción. Esto significa que debes incluir cualquier código dependiente en la función de devolución de llamada o en las funciones ejecutadas por la función de devolución de llamada.
  3. makeRequest() devuelve un objeto JavaScript con la siguiente estructura:
{
  data : <parsed data, if applicable>,
  errors : <any errors that occurred>,
  text : <raw text of the response>  
}  

Este objeto es el único argumento disponible para la función de devolución de llamada. La función de devolución de llamada realiza algunas operaciones en los datos devueltos. Normalmente, extrae porciones de los datos, las combina con las etiquetas HTML e inserta el HTML resultante en el gadget.

Uso de diferentes tipos de contenido

De forma predeterminada, el contenido de un sitio web remoto se devuelve en forma de texto. El campo opt_params permite establecer el tipo del contenido devuelto como uno de los siguientes:

  • TEXT -- gadgets.io.ContentType.TEXT
  • DOM -- gadgets.io.ContentType.DOM
  • FEED -- gadgets.io.ContentType.FEED
  • JSON -- gadgets.io.ContentType.JSON

Uso de texto

Éste es un ejemplo que extrae datos de un archivo CSV (valores separados por coma) y los utiliza para rellenar una lista de contactos personales. Muestra cómo establecer el tipo del contenido extraído en los parámetros opcionales. En la función de devolución de llamada response(obj), el valor de texto se extrae de obj mediante 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>

Uso de XML

DOM (Document Object Model) es un API que permite desplazarse por documentos HTML y XML. Puedes utilizar makeRequest() para recuperar un documento XML como un objeto DOM. Una vez que tengas el objeto, podrás trabajar con él utilizando funciones estándar DOM JavaScript. Normalmente, esto supone extraer los datos deseados del archivo XML, combinarlos con las etiquetas HTML y CSS y representar el HTML resultante en tu gadget.

Con DOM, el contenido web se procesa en un árbol de nodos. Toma como ejemplo el siguiente fragmento de HTML:

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

Este fragmento ilustra los tipos principales de nodos tratados en esta sección:

  • Nodos de elemento. Los nodos de elemento de este fragmento son "a" y "b". Los nodos de elemento son los componentes básicos que definen la estructura de un documento.
  • Nodos de texto. Los nodos de texto de este fragmento son "Google’s", "fast" y "home page". Los nodos de texto siempre están contenidos en los nodos de elemento. Son nodos secundarios del nodo de elemento al que pertenecen.
  • Nodos de atributo. Este fragmento sólo tiene un nodo de atributo: href=’http://www.google.com’. Un nodo de atributo proporciona información adicional sobre el nodo de elemento al que pertenece. Sin embargo, los atributos no se consideran nodos secundarios del elemento al que pertenecen, lo que afecta a la forma en la que se debe trabajar con ellos. Para obtener información más detallada sobre este tema, consulta Uso de diferentes tipos de nodos.

Ésta es la estructura DOM del fragmento de HTML:

Árbol DOM

Para acceder a los datos de un objeto DOM, puedes "navegar por el árbol" mediante las funciones DOM para desplazarte por las relaciones entre nodos principales y secundarios y obtener los datos que necesites.

Ejemplo

El siguiente archivo XML contiene datos de una serie de elementos de desayuno. El nodo principal que aparece primero es el nodo menu, que tiene varios nodos secundarios food (comida). El nodo menu también contiene un nodo de atributo: title="Breakfast Menu". Cada nodo food tiene los nodos secundarios name (nombre), price (precio), description (descripción) y calories (calorías).

Los nodos name, price y calories contienen sus propios nodos secundarios de "texto". Cada nodo description contiene el nodo secundario CDATA. CDATA es un tipo de nodo distinto. Las secciones CDATA permiten aplicar formato de escape a los bloques de texto que contienen caracteres (como los paréntesis angulares) que, de lo contrario, se considerarían etiquetas. El único delimitador reconocido en una sección CDATA es la cadena "]]>", que pone fin a la sección 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>

En el siguiente gadget de ejemplo se utiliza este archivo XML como fuente de datos. Muestra un menú de desayuno que permite al usuario establecer un límite de calorías. Muestra en rojo las calorías que superan el límite especificado. Los usuarios también pueden elegir si desean ver las descripciones de cada artículo del desayuno.

El código siguiente muestra cómo navegar por el árbol DOM para extraer datos de distintos tipos de nodos y cómo combinar los datos con etiquetas CSS y HTML para mostrarlos en el gadget del menú de desayuno.

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

Este código de ejemplo muestra cuatro de las funciones principales que te permitirán interactuar con los datos DOM:

  • getElementsByTagName(tagname): para un documento DOM, devuelve un conjunto de los nodos de elemento cuyos nombres coinciden con tagname. Para recuperar todos los nodos de elemento en un archivo, utiliza el carácter comodín (*), por ejemplo: response.getElementsByTagName("*").
  • getElementById(id): para un documento DOM, recupera un único nodo por su ID.
  • getAttribute(attrib): para un nodo de elemento, devuelve el atributo attrib. Por ejemplo: response.getElementsByTagName("menu").item(0).getAttribute("title").
  • attributes: para un nodo de elemento, devuelve un conjunto de atributos de nodo.

Este ejemplo sólo muestra algunas de las funciones diferentes de navegación por un árbol DOM. También puedes probar otras como lastChild, nextSibling, previousSibling y parentNode.

Uso de diferentes tipos de nodos

La clave para trabajar de forma eficaz con COM es apreciar las diferencias, a veces sutiles, entre los distintos tipos de nodo.

Tipo de nodo Descripción Valores de retorno Significado
element Los componentes básicos estructurales de un documento, como <p>, <b> o <calories>. nodeName: el texto contenido entre los paréntesis angulares. Por ejemplo, nodeName de <menu> es "menu".

nodeType: 1

nodeValue : null
Un elemento tiene un nodeValue de null. Para obtener el valor de un nodo de texto o atributo asociado a un elemento, deberás ir a estos nodos. Por ejemplo: element.firstChild.nodeValue para texto y element.getAttribute(attrib) para atributos.
text Texto. Un nodo de texto siempre está contenido dentro de un elemento. Es un elemento secundario del elemento. nodeName: #text

nodeType: 3

nodeValue: el texto contenido en el nodo.
Algunos navegadores representan todo el espacio en blanco de un documento como nodos de texto, de forma que se obtienen nodos de texto "vacíos" en tu objeto DOM. Esto puede provocar resultados inesperados cuando estás navegando por el árbol. La solución puede consistir simplemente en excluir nodos de texto que contengan sólo el carácter de salto de línea, pero puedes manipular los datos de una forma más compleja si lo deseas. Para obtener información más detallada sobre este tema, consulta Espacio en blanco en el DOM.
attribute Un par clave-valor que proporciona información adicional sobre un nodo de elemento (por ejemplo, title="mi documento"). Un atributo está contenido dentro de un nodo de elemento, pero no es un elemento secundario del nodo de elemento. nodeName: el valor de la izquierda del par de atributos. Si el atributo es title="mi documento", el nodeName sería title.

nodeType: 2

nodeValue: el valor de la derecha del par de atributos (en este ejemplo, "mi documento").
Aunque los atributos son nodos y están contenidos dentro de nodos de elemento, no son nodos secundarios del elemento. Se heredan de la interfaz Node, pero el DOM no los considera parte del árbol DOM. Esto significa que, aunque puedes utilizar muchas de las funciones de nodo en nodos de atributo, como nodeName, nodeValue y nodeType, no puedes acceder a los nodos de atributo mediante las funciones de navegación del árbol DOM. Para acceder a los atributos, utiliza las funciones attributes y getAttribute(attrib).
CDATA Una sección cuyo contenido se ignora y no se interpreta. Las secciones CDATA permiten aplicar formato de escape a los bloques de texto que contienen caracteres que, de lo contrario, se considerarían etiquetas. El único delimitador reconocido en una sección CDATA es la cadena "]]>", que pone fin a la sección CDATA. nodeName: #cdata-section

nodeType: 4

nodeValue: texto y etiquetas dentro de los delimitadores CDATA.

El texto de la sección CDATA dispone de sus propias etiquetas. Esto podría afectar a la forma en la que se debe incorporar al gadget.
Otros recursos

Uso de feeds

Para añadir un feed a tu página de iGoogle, introduce la URL correspondiente en el formulario Añadir por URL del directorio de contenido. Se utilizarán las funciones para feeds incorporadas del API para crear un gadget para el feed y añadirlo a iGoogle. Este sistema es sencillo, pero no permite personalizar ni mostrar el contenido. Además, no permite utilizar los feeds con otros contenedores.

Para utilizar los feeds de una forma más sofisticada, puedes utilizar el método makeRequest() y especificar un tipo de contenido FEED. Las solicitudes de feed se realizan para que se analice un feed XML, RSS o ATOM y se obtenga un objeto con codificación JSON como respuesta.

Con un tipo de contenido FEED, puedes especificar los siguientes parámetros:

Parámetro Tipo de datos Descripción
gadgets.io.RequestParameters.NUM_ENTRIES Número, opcional El número de entradas que se deben recuperar del feed. El rango aceptado es de 1 a 100. El valor predeterminado es 3.
gadgets.io.RequestParameters.GET_SUMMARIES Booleano, opcional Indica si deben recuperarse los resúmenes completos de texto de las entradas del feed. El valor predeterminado es "false". El valor sólo debe definirse en "true" si se desean utilizar los datos. Los resúmenes completos pueden ser bastante extensos y no deben transferirse si no es absolutamente necesario.

Éstos son los campos del objeto feed JSON:

Campo Descripción
ErrorMsg Si está definido, describe cualquier error que se haya producido.
URL URL del feed RSS/Atom
Title Título del feed
Description Lema o descripción del feed
Link Habitualmente, la URL de la página principal del feed
Author Autor del feed
Entry Conjunto de entradas de feeds. Los campos siguientes se encuentran anidados en Entry:
  • Title. Título de esta entrada de feed.
  • Link. URL de esta entrada de feed.
  • Summary. El contenido o resumen de esta entrada de feed.
  • Date. Marca de tiempo de la entrada en segundos desde el 1 de enero de 1970. Para convertir este valor en los milisegundos necesarios para inicializar un objeto Date de JavaScript con la fecha correcta, debes multiplicarlo por 1.000. Consulta el código del gadget de muestra siguiente a modo de ejemplo.

Tome como ejemplo este feed 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>

Si extrae el feed anterior con el tipo de contenido FEED, el valor mostrado se codifica en forma de cadena JSON del siguiente modo:

{"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()"
}
    

En el ejemplo siguiente se muestra cómo utilizar makeRequest() para extraer un feed y mostrar partes de sus datos en un gadget. Éste es el gadget. Extrae un feed que contiene entradas del foro de desarrolladores de gadgets. Permite a los usuarios especificar:

  • el número de entradas que se deben mostrar,
  • si el gadget debe mostrar la fecha de cada entrada,
  • si el gadget debe mostrar un resumen de cada entrada.

Éste es el código del ejemplo:

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

Uso de JSON

JSON (JavaScript Object Notation, Notación de objetos JavaScript) es un formato de intercambio de datos que permite codificar determinados tipos de objetos (matrices y grupos de pares clave-valor) como cadenas que se pueden transmitir fácilmente. Puedes utilizar el tipo de contenido JSON para extraer contenido con codificación JSON como un objeto JavaScript.

El gadget que se muestra a continuación extrae contenido de un archivo de texto que contiene la siguiente cadena con codificación JSON:

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

Si extraes contenido del archivo de texto que contiene esta cadena, el valor de retorno será un objeto JavaScript que contenga pares clave-valor (es decir, una matriz asociativa). En este ejemplo se recupera el objeto y se imprimen a continuación los pares clave-valor que contiene. Si el valor es un conjunto (indicado con corchetes []), devuelve el contenido del conjunto en forma de lista con viñetas:

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

La información que aparece en el gadget es la siguiente:

Name: Rowan
Breed: Labrador Retriever
Hobbies:

  • fetching
  • swimming
  • tugging
  • eating

Más información sobre JSON

El API de gadgets proporciona el método gadgets.json.stringify() para la codificación de objetos como cadenas JSON y el método gadgets.json.parse() para convertir una cadena JSON en un objeto. Ten en cuenta que OpenSocial ejecuta automáticamente secuencias de escape HTML de todos los datos obtenidos, incluidos los datos de la aplicación, por lo que deberás anular el escape de los objetos JSON convertidos en cadenas del almacén appdata antes de analizarlos. Por ejemplo: gadgets.util.unescapeString(jsondata)

Este ejemplo permite crear una matriz JavaScript, codificarla como una cadena JSON y volver a convertir después esa cadena en un objeto "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>

Los resultados de este gadget serían los siguientes:

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

Establecimiento de un tipo de autorización

El API de gadgets admite los siguientes tipos de autorización:

  • gadgets.io.AuthorizationType.OAUTH (el contenedor utiliza el protocolo OAuth)
  • gadgets.io.AuthorizationType.SIGNED (el contenedor firma la solicitud)
  • gadgets.io.AuthorizationType.NONE (opción predeterminada)

La forma de utilizar estos métodos depende del contenedor. A continuación se muestra un ejemplo de uso de un tipo de autorización firmada específico de orkut. Si deseas saber más sobre el uso del protocolo OAuth en los gadgets, consulta la sección Creación de gadgets de OAuth.

Métodos

makeRequest() permite elegir entre los métodos GET HTTP y POST HTTP.

GET

Normalmente, se utiliza el método GET para recuperar información de un sitio web. GET es el modo predeterminado de makeRequest(), pero se puede realizar una solicitud GET de forma explícita del siguiente modo:

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"); 

Para transmitir parámetros al servidor a través de la solicitud GET, sólo hay que añadirlos a la cadena de consulta al realizar la solicitud:

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

POST

Las solicitudes POST se suelen utilizar para transmitir datos a un servidor con la intención de modificar o eliminar registros. Las solicitudes POST permiten transmitir una cantidad de datos superior a la que se puede transmitir normalmente a través de las solicitudes GET.

Podemos crear una solicitud POST con el siguiente código:

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); 

Además de especificar el método (METHOD) en el argumento opt_params de esta solicitud, se debe especificar un parámetro en la clave gadgets.io.RequestParameters.POST_DATA. POST utiliza de forma predeterminada application/x-www-form-urlencoded, una codificación que indica que el valor del parámetro POST_DATA debe consistir en una serie de pares clave/valor unidos por ampersands (&) con codificación URL. La inclusión de la función gadgets.io.encodeValues en la solicitud facilita la conversión de objetos de datos a este formato. encodeValues acepta un objeto JavaScript y devuelve una cadena codificada adecuada para el parámetro POST_DATA.

Por ejemplo, al ejecutar:

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

se obtiene la cadena:

data1=test&data2=123456 

Esta cadena se puede transmitir directamente como valor de gadgets.io.RequestParameters.POST_DATA.

Actualización de la memoria caché

Si estás utilizando makeRequest() para extraer contenido que se actualiza más de una vez cada hora, como datos de feeds, es posible que no obtengas los datos más actualizados. Esto se debe a que los resultados se almacenan en la memoria caché para que tu gadget se ejecute más rápido. Si quieres asegurarte de que tu gadget disponga de los datos más recientes, puedes utilizar el parámetro refreshInterval para omitir el almacenamiento en caché y forzar una actualización dentro del intervalo especificado. En otras palabras, la memoria caché se actualizará cada X segundos, donde X = refreshInterval.

Las llamadas a makeRequest se almacenan en la memoria caché de forma predeterminada. En el ejemplo siguiente, la función envoltorio utiliza los mismos parámetros que la llamada makeRequest, pero acepta otro parámetro denominado refreshInterval, que permite especificar la duración del almacenamiento en caché.

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);
}

El almacenamiento en caché tiene una finalidad y se debe tener cuidado de no limpiar la memoria caché con una frecuencia excesiva que afecte al rendimiento. El almacenamiento en caché aumenta la velocidad de extracción de los datos. También reduce la carga de los servidores externos en los que se aloja el contenido remoto. Intenta evitar la completa inhabilitación del almacenamiento en caché (que se produce al establecer el valor refreshInterval: 0). Si tu gadget recibe millones de visitas cada día y envía millones de solicitudes a estos servidores, desactivar la memoria caché no sólo afectaría de forma negativa al rendimiento de tu gadget, sino que además sobrecargaría los servidores que le proporcionan los datos.

Dado que el contenido se actualiza de forma predeterminada cada hora, sólo tendría sentido especificar un intervalo inferior a una hora. El intervalo recomendado para refreshInterval sería superior a 60 e inferior a 3600.

Volver al principio