处理远程内容

本文档介绍了如何提取和控制远程文本(通常为 HTML)、XML、JSON 和 RSS/Atom 供稿数据。

目录

  1. 简介
  2. 处理不同的 Content 类型
    1. 处理文本
    2. 处理 XML
    3. 处理供稿
    4. 处理 JSON
  3. 设置授权类型
  4. 方法
    1. GET
    2. POST
  5. 刷新缓存

简介

小工具提供的最令人振奋的一个功能是能以新方式组合多个源中的信息,或提供备用方式与现有信息进行交互。小工具 API 使您的小工具可以远程提取其他网络服务器和网页的内容并对其进行操作。

小工具 API 提供了 makeRequest(url, callback, opt_params) 函数以进行检索和操作远程网络内容。该函数将使用以下参数:

  • String url - 存放内容的网址
  • Function callback - 提取网址后,与来自该网址的数据一起调用的函数
  • Map.<gadgets.io.RequestParameters, Object> opt_params - 传送给请求的其他参数。

使用 opt_params 参数可以指定以下内容:

  • 请求的 Content 类型(TEXTXMLFEEDJSON
  • 请求的方法类型(POSTGET
  • 您想在请求中包含的任意标题
  • 授权类型(NONESIGNEDOAUTH

请注意:您不能配合使用 makeRequest()type="url" 小工具。

不管提取的数据类型为何,对 makeRequest() 的调用都有以下相同特征:

  • 第一个参数是用来提取远程内容的网址。
  • 第二个参数是用来处理返回的数据的回调函数。
  • 它们是异步的,这意味着所有处理操作都必须在回调函数内进行。回调是作为参数(以函数引用的形式)传递给其他函数的函数。回调使第三方开发人员可以“挂”入运行的框架进行某些处理。
  • 由于立即返回,因此它们没有返回值,每当响应返回时,都将调用其关联的回调函数。

例如,假设使用以下提取远程内容作为文本的代码段。该代码提取 google.com 网页的 HTML 文本并显示前 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 请求(在本实例中,网址是 http://www.google.com)。
  2. makeRequest() 在提取结束后立即返回,然后会在稍后调用回调函数(在本实例中调用了 response())。这意味着您必须将任意独立代码放入回调函数内或回调函数调用的函数内。
  3. makeRequest() 使用以下结构返回 JavaScript 对象:
{
  data : <parsed data, if applicable>,
  errors : <any errors that occurred>,
  text : <raw text of the response>  
}  

该对象作为唯一的参数提供给回调函数。回调函数对返回的数据执行某些操作。通常它会提取数据部分,将其与 HTML 标记结合并将得到的 HTML 提交到小工具中。

处理不同的 Content 类型

默认情况下,远程网站的内容以文本形式返回。您可以使用 opt_params 字段将返回内容的 Content 类型设置为以下类型之一:

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

处理文本

以下是从 CSV(逗号分隔值)文件提取数据并用其填充个人联系人列表的示例。它显示了如何通过可选参数设置提取内容的 Content 类型。在 response(obj) 回调函数中,文本值是使用 obj.textobj 中提取的:

<?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) 是用于浏览 HTML 和 XML 文档的 API。您可以使用 makeRequest() 来检索作为 DOM 对象的 XML 文档。拥有该对象后,可以使用标准 DOM JavaScript 函数对其进行操作。这通常意味着从 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’。属性节点提供有关它所包含的元素节点的其他信息。但是,不能将属性视为包含它们的元素的子节点,其中暗含了如何处理这些节点。有关该主题的更多讨论内容,请参阅处理不同的节点类型

以下是 HTML 代码段的 DOM 结构:

DOM 树

要访问 DOM 对象中的数据,您可以“遍历该树”(使用 DOM 函数浏览父子节点关系直至找到所需数据)。

示例

以下 XML 文件包含一系列早餐项的数据。最上面的父节点是 menu,它有多个 food 子节点。menu 节点还包含属性节点:title="Breakfast Menu"。每个 food 节点都有 namepricedescriptioncalories 子节点。

namepricecalories 节点都包含它们自己的“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 文档,按 ID 检索单个节点。
  • getAttribute(attrib)-- 对于元素节点,返回属性 attrib。例如:response.getElementsByTagName("menu").item(0).getAttribute("title")
  • attributes -- 对于元素节点,返回节点属性的数组。

该示例仅显示了用于浏览 DOM 树的几个不同功能。您可能想尝试的某些其他功能包括 lastChildnextSiblingpreviousSiblingparentNode

处理不同的节点类型

有效使用 DOM 的关键在于重视不同节点类型间的某些细微差别。

节点类型 说明 返回值 说明
element 文档的结构性组件,例如 <p><b><calories> nodeName:尖括号中包含的任意文本。例如,<menu>nodeName“menu”

nodeType:1

nodeValuenull
元素的 nodeValuenull。要浏览至与元素的文本节点或属性节点相关联的值,您必须转至这些节点。例如:用于文本的 element.firstChild.nodeValue 和用于属性的 element.getAttribute(attrib)
text 文本。文本节点始终包含在元素中。它是元素的子节点。 nodeName#text

nodeType:3

nodeValue:节点中包含的任意文本。
有些浏览器会将文档中所有的空白均作为文本节点提交,这样您便会在 DOM 对象中得到“空”文本节点。这可能会在您遍历树时导致意想不到的结果。解决方法很简单,就如同过滤出仅包含换行符的文本节点一样,或者可以进行更强的处理。有关该主题的更多讨论内容,请参阅 DOM 中的空白
attribute 提供有关元素节点的其他信息的键-值对(例如,title=”my document”)。属性包含在元素节点中,但不是该元素节点的子节点。 nodeName:属性对中的左侧值。如果属性是 title=”my document”,则 nodeNametitle

nodeType:2

nodeValue:属性对中的右侧值(在本示例中为“my document”)。
即使属性是节点并包含在元素节点内,它们也不是元素节点的子节点。它们继承自节点界面,但 DOM 并不将它们视为 DOM 树的一部分。这意味着尽管您可以使用属性节点上的许多节点函数(如 nodeNamenodeValuenodeType),但您不能使用 DOM 树遍历函数访问属性节点。要访问属性,您可以使用函数 attributesgetAttribute(attrib)
CDATA 内容保留而不被解释的部分。CDATA 部分用来转义包含字符的文本块,如不进行转义,这些字符会被视为标记。CDATA 部分中识别的唯一分隔符是结束 CDATA 部分的“]]>”字符串。 nodeName#cdata-section

nodeType:4

nodeValue:CDATA 分隔符内的文本和标记。

CDATA 部分中的文本有其自己的标记。这可暗示您如何将其整合至小工具中。
其他资源

处理供稿

您可以通过将供稿的网址键入内容目录的按网址添加表单中来向 iGoogle 页面添加该供稿。这使用小工具 API 内置供稿支持来为供稿创建小工具并将其添加至 iGoogle。它简单易用,但不允许您对内容或显示执行任何自定义操作。另外,您也不能将其与其他容器配合使用。

要处理更复杂的供稿,您可以使用 makeRequest() 方法并指定 FEED Content 类型。供稿请求尝试解析 ATOM 或 RSS XML 供稿并将响应作为 JSON 编码的对象返回。

使用 FEED Content 类型,您可以指定以下参数:

参数 数据类型 说明
gadgets.io.RequestParameters.NUM_ENTRIES 数字,可选 要从供稿检索的供稿条目的数量。可接受范围为 1 到 100。默认为 3。
gadgets.io.RequestParameters.GET_SUMMARIES 布尔值,可选 是否检索供稿中的条目的全文摘要。默认为 False。仅当您计划使用数据时,才应设置为 True。全部摘要可以非常多,不应徒劳地进行转移。

下面是 JSON 供稿对象中的字段:

字段 说明
ErrorMsg 如果已定义,描述发生的任何错误。
URL RSS/Atom 供稿的网址。
Title 供稿的标题。
Description 供稿的标签行或说明。
Link 通常是供稿主页的网址。
Author 供稿的作者。
Entry 供稿条目的数组。以下字段嵌套在条目中:
  • Title。该供稿条目的标题。
  • Link。该供稿条目的网址。
  • Summary。该供稿条目的内容或摘要。
  • Date。该条目的时间戳,从 1970 年 1 月 1 日开始,以秒为单位。要用正确的日期将其转换为初始化 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 Content 类型提取以上供稿,则返回的值编码为 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 对象表示法)是数据交换格式,使您可以将某些对象类型(键-值对的数组和集合)作为可以轻松传递的字符串进行编码。可以使用 JSON Content 类型作为 JavaScript 对象提取 JSON 编码的内容。

以下小工具将从包括以下 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
品种:拉布拉多寻回犬
爱好:

  • 取物
  • 游泳
  • 拖东西
  • 吃东西

有关 JSON 的更多信息

小工具 API 提供 gadgets.json.stringify() 方法分以将对象编码为 JSON 字符串,并提供 gadgets.json.parse() 方法以将 JSON 字符串转换为对象。请注意,因为 OpenSocial 执行自动 HTML(对所有包括应用程序数据的返回数据进行编码),所以必须在解析它们之前对应用程序数据存储中字符串化的 JSON 对象进行解码,例如:gadgets.util.unescapeString(jsondata)

该实例创建了 JavaScript 数组,并将其编码为 JSON 字符串,然后将 JSON 字符串转换回数组对象:

<?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 从网站检索信息。GET 是 makeRequest() 的默认模式,但是您可如下明确提出 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); 

除了通过 opt_params 为该请求指定 METHOD 外,您还应在键 gadgets.io.RequestParameters.POST_DATA 下指定参数。POST 的默认编码为 application/x-www-form-urlencoded,这意味着 POST_DATA 参数的值应是与和号 (&) 相结合的一系列网址编码的键/值对。为将数据对象更方便地转换为该格式,提供函数 gadgets.io.encodeValuesencodeValues 接受 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 秒刷新一次,其中 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。

返回页首