IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Open source | XML  >

用 XPath 在 PHP Web 站点中显示 Google Calendar 事件

XPath 和 SimpleXML 为 XML 解析 API 提供可读性与冗余性权衡

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 中级

P.J. Cabrera (pjcabrera@pobox.com), 软件工程师, 自由作家

2008 年 1 月 10 日

Google Calendar 和其他在线日历应用程序将提供简单的集中式系统,在这类系统中,在线社区可以维护事件日历,而社区成员可以获得关于最新事件的信息。但是许多组织更倾向于在其社区门户、论坛或博客中显示事件日历。他们经常把事件日历信息从在线日历应用程序复制到 Web 站点中,降低了在线集中管理事件的效率。Google Calendar 提供了集成应用程序接口 (API),从而为这个问题提供了很好的解决方案。了解如何使用 XPath 提取并在 PHP Web 站点中显示 Google Calendar 数据。

当几年前我是一名自由 Web 开发人员时,我为一个特殊车型汽车的拥有者和爱好者社区(通常称为汽车俱乐部,它们在我生活的地方非常流行)开发了一个用 PHP 编写的 Web 门户。在联系我的几年以前,一些汽车俱乐部管理者就已经学习了基本的 Web 技巧并且自己创建了一个 Web 站点。随着站点的成长,站点积聚了大量页面,其中一些发布了单独的事件日历信息的页面已经失效。由于站点的主要目的是向公众及社区成员通知活动,因此这些页面中插入了事件日历信息。

随着时间的推移,这些社区事件日历的不同快照不同步了。虽然很多事件已经过去很久了,但页面中仍然保留有与之相关的侧栏。即使有正确的管理和有效的 Web 设计,维护各个网页中事件日历数据的各个副本也是一项花费大量时间和容易出错的任务。他们发现不是汽车俱乐部 Web 站点在为他们工作,而是自己在为那个 Web 站点工作。他们联系到我,希望我能给他们展示一种更好的方法。

他们希望站点中有论坛,俱乐部成员可以在其中讨论他们喜爱的汽车,还要有一个集中的新闻页面,用于发布最新的事件报导和通告。在这个新闻页面中,他们可以向不断增多的成员通知事件,例如联欢会、自驾车到野外和乡村游玩以及讨论成员交费和预算事项的全体成员会议。更重要的是,他们希望不必维护位于各个位置的多个事件日历副本。希望在一个位置输入事件日历并且能够在站点中的任意位置访问该信息。

Google Calendar 和 Google 数据 API

在线日历应用程序(如 Google Calendar)提供了一种解决方案。通过集中显示和管理事件,Google Calendar 用户可以在一个站点中共享和维护事件日历,消除了事件组织过程中可能造成错误的其中一个源头。社区成员可以访问在线日历来获悉最新事件和活动,而不会由于各个 Web 页面中过时的事件信息而导致混乱。看上去在线日历应用程序是十分理想的解决方案。

在用 Drupal 内容管理系统(请参阅 参考资料)开发俱乐部的 Web 站点时,我建议俱乐部的管理者使用 Google Calendar 来维护事件日历。最初,这个建议得到了认同,并且他们反馈说效率很高,因为可以轻松地使用 Drupal 管理前端来更新我为他们创建的事件侧栏。但是随着时间的推移,俱乐部的成功意味着有更多事件需要通告,而编辑事件侧栏也从轻松有趣变得愈加繁琐。

Google 数据 API 及其对 Google Calendar 事件数据的访问权提供了一种摆脱这种困境的方法。Google 数据 API 提供了一个 Atom 发布协议(Atom Publishing Protocol,APP)的实现,这是用于读取和更新各种类型的文档和信息的 Web 服务 API。还有适用于 Microsoft® .NET、Java™ 编程语言、Python 和 PHP 的第三方集成 API,这些集成 API 在一组面向对象的封装类中封装了大部分 Google 数据 API 功能。

经过一些研究之后,我能够把汽车俱乐部的 Drupal 站点扩展为拥有一直保持最新信息的事件侧栏,该侧栏将从 Google Calendar 帐户中提取最新的事件日历数据。





回页首


Google Calendar 摘要

Google 数据 API 将提供大量包含由 Google 提供的许多 Web 服务的文档和信息的 Atom 摘要。Google Calendar 也不例外,提供了一些封装了主要 Google Calendar 数据的摘要。有经过 HTTP 验证的公共摘要。要检索并与经过验证的摘要进行交互,HTTP 客户需要提供验证信息以及 HTTP GET 请求。经过验证的摘要还能够用 HTTP POST 请求来更新 Google Calendar 帐户。使用经过验证的摘要的 HTTP 客户可以添加和删除事件,订阅和取消订阅日历,以及创建日历和从 Google 帐户中删除日历。

Google Calendar API 提供了用户可以从 Google Calendar GUI 访问的所有单独日历的摘要。这包含用户所拥有的日历、其他人所拥有但是用户已经订阅的日历,以及用户已经以只读状态导入的日历。这些日历都有各自经过验证的私有和公共事件摘要,其中列出了日历中的各个事件。本文介绍的重点是公共事件摘要。

使 Google Calendar 摘要成为公共摘要

一个账户可以有许多 Google Calendar 日历的公共事件摘要,获得摘要的方法是登录到 Google Calendar 应用程序中,选择有兴趣处理的日历,并单击日历名称的向下小箭头。单击此箭头后,摘要名称旁边将显示一个菜单。选择 Calendar Settings,图 1 中被圈选的部分。


图 1. 所选日历的 Google Calendar 下拉菜单


然后 Google Calendar 应用程序将转到可以选择各个日历设置(例如事件的时区和日历名称)的页面。公共摘要的一个重要选项是日历本身是公共的还是共享的 日历。要使日历共享并且可以通过公共事件摘要来检索,请单击 Change sharing settings 选项,如图 2 所示:


图 2. 将日历的可视性更改为共享或公共


页面将转到可以选择 Share all information on this calendar with everyoneShare this calendar 选项卡。系统将显示一系列弹出式问题,询问您是否确实要使日历公开。回答 Yes,并且不要忘记单击选项卡底部的 Save 来保存设置。单击 Back to Calendar 继续向日历中添加事件。

检验 Google Calendar 摘要

要获得 Google Calendar 摘要的示例,请参考 下载 部分中提供的代码样例中的 full.xml 文件。我还提供了本文中使用的代码示例的虚构摘要链接(请参阅 参考资料)。

事件摘要包含描述事件的各个元素,例如事件标题、描述以及事件发生的时间和地点。Google Calendar 还管理了一张受邀参加事件的人员列表,只要事件有更新就通过这些人员的电子邮件列表发送事件详细信息。如果这些电子邮件地址表示 Google Calendar 用户,那么他们可以通过应用程序响应邀请,并且事件还将保存他们的出席状态。集成出席详细信息不在本文讨论的范围内,出席详细信息描述的是基本事件信息,例如事件标题和事件发生的时间和地点。清单 1 是样例摘要中的一个事件条目。


清单 1. 样例 Google Calendar 事件摘要条目:ID 和时间戳
                
    <entry>
	    <id>
            http://www.google.com/calendar/feeds/foss.sanjuan%40gmail.com/public/full/
            s19o15ve3nn209gv5qf6c43ao4
        </id>
        <published>2007-08-12T15:45:40.000Z</published>
        <updated>2007-08-12T15:53:37.000Z</updated>
        ...
        ...

id 元素将提供用于在 Google Calendar 系统内识别此事件的惟一统一资源标识符(Uniform Resource Identifier,URI)。它不但包含惟一编号,而且还标识了检索到它时所在的摘要。publishedupdated 元素将使用 RFC 3339 时间戳格式。updated 元素用于指示最后一次编辑事件的时间,如果是新事件,则是事件的创建时间。

在增加了 idpublishedupdated 元素后,元素中就有了更多可读信息,如清单 2 所示。此信息可以显示在侧栏或事件页面中。


清单 2. 样例 Google Calendar 事件摘要条目:标题、作者和状态
                
        ...
        ...

        <title type="text">Linux Install Fest</title>
        ...
        ...

        <author>
            <name>Open Source San Juan</name>
            <email>foss.sanjuan@gmail.com</email>
        </author>
        ...
        ...

        <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
        ...
        ...

title 元素是一个标识事件的简单字符串。它不必惟一。author 元素包含 nameemail 元素。事件的作者是把事件输入到日历中的 Google Calendar 用户。在相应地设置了经过验证的摘要和写访问权限后,除了日历的拥有者之外 Google Calendar 用户也可以在其他用户的日历中创建事件。表 1 描述了 status 元素的可能值。


表 1. gd:eventStatus 元素的可能值
描述
http://schemas.google.com/g/2005#event.cancelled事件被取消。
http://schemas.google.com/g/2005#event.confirmed事件被确认。
http://schemas.google.com/g/2005#event.tentative事件已暂时排定。

接下来是描述事件发生的时间和地点的元素,如清单 3 所示:


清单 3. 样例 Google Calendar 事件摘要条目:时间和地点
                
        ...
        ...

        <gd:when startTime="2007-08-03T16:00:00.000-04:00" 
            endTime="2007-08-03T19:00:00.000-04:00"/>
        <gd:where 
            valueString="Guaynabo Public High School Auditorium, Guaynabo, PR"/>
    </entry>

when 元素包含两个属性:事件的开始时间和结束时间,两者都使用 RFC 3339 时间戳格式。where 元素的 valueString 属性是可以从 Google Calendar 应用程序和通过 API 来完全检索的。Google Calendar 和 Google 数据 API 不支持按个别元素搜索。相反,他们将对 string 元素(例如 titleauthordescription,以及 where 元素的 valueString 属性)进行全文搜索。正如您稍后将看到的,例外情况是 Google 数据 API 支持设置开始日期范围以限制查询结果中包括的事件。

限制 Google Calendar 摘要的内容

为了支持检索精确数据集,Google 数据 API 在 HTTP GET 请求中支持查询参数的概念。使用这些参数,Google 数据 API 客户可以指定要返回的最大条目数(使用 max-results 参数),使用哪些元素对摘要条目进行排序(通过 orderby 参数),以及要返回的条目范围包含的开始时间和结束时间(通过 start-minstart-max 参数)。最后这两个参数指示要包含在事件结果集中的事件开始时间的日期范围。start-min 是指范围的开始日期,start-max 是指范围的结束日期。两个参数都是用 RFC 3339 时间戳格式表示的。

最后,可以通过在查询字符串中包含 singleevents 参数使重复出现的事件更易于解析。当 singleevents 参数的值为 true 时,系统将把重复出现的事件视为明显的单个事件在摘要中指定。否则,重复出现的事件将包括 <gd:recurrence> 元素,该元素包含 iCal 格式的重复出现规则。iCal 格式以及如何解析该格式不在本文讨论的范围内。

清单 4 是添加了所有查询参数后事件摘要 URL 的显示内容。编写时为了具有可读性,把一个长的 URL 断开成了若干行。


请单 4. 带有查询参数的样例 Google Calendar 摘要 URL
                
    http://www.google.com/calendar/feeds/foss.sanjuan%40gmail.com/public/full?
    max-results=25&
    singleevents=true&
    orderby=starttime&
    start-min=2007-05-22T09%3A58%3A47-04%3A00&
    start-max=2007-11-06T09%3A58%3A47-04%3A00





回页首


用 PHP 解析 Google Calendar 摘要

既然已经讨论了 Google Calendar 事件摘要的元素和如何查询摘要以获得感兴趣的条目,接下来将探讨解析摘要和在页面中显示摘要的方法。PHP 提供了若干个可用于检索事件条目列表和提取每个事件的标题、日期、时间和位置的 XML API。首先将从文档对象模型(Document Object Model,DOM)API 开始。

用 DOM 解析摘要

XML DOM API 是一个标准的 XML 解析 API,而且它最常用于编写 XML 应用程序。DOM API 的用法不在本文讨论的范围内,但是我将详细介绍解析 Google Calendar 事件摘要的示例程序,并说明 DOM API 的一些优点和缺点。

XML DOM API 的优点之一是速度很快。它将把整个 XML 文档装载到内存中,并且从 XML 文档中检索元素全都在内存中进行。不过这样做对于大型的 XML 文件来说效率很低,它只适用于 2 MB 或 3 MB 的 XML 文件。

XML DOM API 的另一个优点是可读性。用 DOM 解析 XML 包含用于打开 XML 文档和从层次结构样式的文档中检索特定元素的命令。它几乎就象英语一样,告诉 PHP 去 “获得带有 ‘entry’ 标记名称的元素”。清单 5 演示了这些内容。


清单 5. 用 DOM API 解析 Google Calendar 事件摘要
                
<?php 
    $confirmed = 'http://schemas.google.com/g/2005#event.confirmed';

    $three_months_in_seconds = 60 * 60 * 24 * 28 * 3;
    $three_months_ago = date("Y-m-d\Th:i:sP", time() - $three_months_in_seconds);
    $three_months_from_today = date("Y-m-d\Th:i:sP", time() + $three_months_in_seconds);

    $feed = "http://www.google.com/calendar/feeds/foss.sanjuan%40gmail.com/" . 
        "public/full?orderby=starttime&singleevents=true&" . 
        "start-min=" . $three_months_ago . "&" .
        "start-max=" . $three_months_from_today;

    $doc = new DOMDocument(); 
    $doc->load( $feed );

    $entries = $doc->getElementsByTagName( "entry" ); 

    foreach ( $entries as $entry ) { 

        $status = $entry->getElementsByTagName( "eventStatus" ); 
        $eventStatus = $status->item(0)->getAttributeNode("value")->value;

        if ($eventStatus == $confirmed) {
            $titles = $entry->getElementsByTagName( "title" ); 
            $title = $titles->item(0)->nodeValue;

            $times = $entry->getElementsByTagName( "when" ); 
            $startTime = $times->item(0)->getAttributeNode("startTime")->value;
            $when = date( "l jS \o\f F Y - h:i A", strtotime( $startTime ) );

            $places = $entry->getElementsByTagName( "where" ); 
            $where = $places->item(0)->getAttributeNode("valueString")->value;

            print $title . "\n"; 
            print $when . " AST\n"; 
            print $where . "\n"; 
            print "\n"; 
        }
    }
?>

在这段代码样例中,将用所需的参数设置摘要 URL,打开摘要,然后获得 DOMNodeList 中的所有事件条目,可以用 foreach 迭代程序来处理。对于每个事件条目,将比较 gd:eventStatus 元素的值属性与确认事件的已知值。注意,无需为 element 标记指定 gd: 前缀。PHP DOM API 知道名称空间,并且需要删除 gd: 前缀,否则解析器将找不到想要的元素。

如果确认了事件条目,则将检索 titlegd:whengd:where 元素。gd:whengd:where 元素要求请求具体属性,例如 startTimevalueString。需要以方便阅读的方法显示事件日期并且解析 gd:when 元素的 startTime 属性将其转换为表示时间的长整数。然后将此信息传递给带有常用显示格式的日期函数。

DOM API 的一个缺点是有些冗长。虽然每条语句的目的十分明确,因为它匹配算法的文本描述,但是它不像代码包一样扼要。DOMNodeDOMDocument 类的 getElementsByTagNamegetAttributeNode 方法将添加相当多的代码。

用 SAX 解析摘要

另一个可用于 PHP 的 XML 解析 API 是 Simple API for XML (SAX) API。DOM API 具有可读性但冗长,而 SAX 可以很简要但难于遵循,即使是对于有经验的开发人员。SAX 与 DOM 之间的差别在于 SAX 不把整个 XML 文档装载到内存中,而 DOM 却这样做。高效的 SAX 处理代码可以快得多,而内存使用量可以保持在最低并且可以根据应用程序的具体需求来调整。使用 DOM,内存使用量要求从应用程序处理的最大 XML 文档大小开始向上攀升。

清单 6 是 SAX 处理 Google Calendar 事件摘要的示例片段。要获得完整示例,请参考 下载 部分中提供的示例脚本包中的 sax_sample.php 脚本。


清单 6. 用 SAX API 解析 Google Calendar 事件摘要
                
    function startElement( $parser, $tagName, $attr )
    {
        global $g_entries, $g_tagName, $g_confirmed, $g_is_confirmed, 
            $g_in_entry, $g_in_originalevent;

        if ( $tagName == 'ENTRY' ) {
            if ($g_is_confirmed || count( $g_entries ) == 0) {
                $g_entries []= array();
            }
            $g_is_confirmed = false;
            $g_in_entry = true;
        }
        else if ($tagName == 'GD:EVENTSTATUS')
        {
            if ($attr['VALUE'] == $g_confirmed) {
                $g_is_confirmed = true;
            }
        }
        else if ($tagName == 'GD:WHEN' && $g_is_confirmed && 
            $g_in_originalevent == false)
        {
            $startTime = date( "l jS \o\f F Y - h:i A", strtotime($attr['STARTTIME']) );
            $g_entries[ count( $g_entries ) - 1 ]['when'] = $startTime;
        }
        else if ($tagName == 'GD:WHERE' && $g_is_confirmed)
        {
            $g_entries[ count( $g_entries ) - 1 ]['where'] = $attr['VALUESTRING'];
        }
        else if ( $tagName == 'GD:ORIGINALEVENT' ) {
            $g_in_originalevent = true;
        }
        $g_tagName = $tagName;
    }

    function endElement( $parser, $tagName ) 
    {
        global $g_tagName, $g_in_entry, $g_in_originalevent;

        if ( $tagName == 'ENTRY' ) {
            $g_in_entry = false;
        }
        else if ( $tagName == 'GD:ORIGINALEVENT' ) {
            $g_in_originalevent = false;
        }
        $g_tagName = null;
    }

    function textData( $parser, $text )
    {
        global $g_entries, $g_tagName, $g_in_entry;
        if ($g_tagName == 'TITLE' && $g_in_entry) {
            $g_entries[ count( $g_entries ) - 1 ]['title'] = $text;
        }
    }

这段代码显示了 startElementendElementtextData 函数,这些函数都是使用 SAX 示例脚本中的 SAX 解析器引擎注册的。这部分代码显示了如何处理感兴趣的几个元素。代码变得十分复杂,因为 SAX 中的 XML 元素是按照从顶部到底部的顺序从 XML 文档中读取的。在处理所需的一些元素之前不能检查当前事件条目是否已确认。例如,gd:eventStatus 元素比 title 元素晚出现在事件中。复杂度的另一个根源是摘要有 title 元素,并且每个条目也有 title 元素。需要设置一个标志让代码知道读取的是不是条目内的 title 元素。重复出现的事件的 gd:originalEvent 元素中还有一个 gd:when 元素,该元素不是您感兴趣的 gd:when 元素。如果没有这个状态检查逻辑,单纯匹配元素名称将生成错误输出。

通过这个示例,您可以看到 SAX API 的两个缺点:它比 DOM API 冗长得多,而且经过与 DOM 样例代码的比较后,SAX 解析器更加复杂。

用 Zend Google API 封装程序解析摘要

Zend Technologies 与 Google 合作扩展了 Zend 框架,为 PHP 提供了一组面向对象类,用于隐藏 Google 数据 API 的 Atom 摘要的详细信息,从而提供对所有 Google 数据信息的支持。这些面向对象类有很多优点,包括将各种 Google 数据 API 文档呈现为具有方法和简单参数的抽象对象,以及隐藏 Atom 摘要和 HTTP 协议操作(例如 GETPUTPOST)的详细信息。这些类还把用户验证的详细信息封装到 Google 数据 API 中,使它更易于写入支持 Google 数据 API 所有功能(例如创建和更新来自第三方客户的事件)的应用程序中。

虽然这样做为不熟悉 XML 解析和 HTTP 协议详细信息的开发人员简化了开发工作,但是 Zend 框架 Google 数据 API 类并非没有缺点。如清单 7 所示,代码十分冗长,因为许多对象构造函数都不带参数。因此,必须在创建对象之后通过属性设置选项。


清单 7. 用 Zend PHP 类请求和处理 Google Calendar 事件摘要
                
<?php
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_Calendar');

$three_months_in_seconds = 60 * 60 * 24 * 28 * 3;
$three_months_ago = date("Y-m-d\Th:i:sP", time() - $three_months_in_seconds);
$three_months_from_today = date("Y-m-d\Th:i:sP", time() + $three_months_in_seconds);

// Create an instance of the Calendar service without authentication,
// for read-only access to a public feed
$service = new Zend_Gdata_Calendar();

$query = $service->newEventQuery();
$query->setUser('foss.sanjuan%40gmail.com');
$query->setVisibility('public');
$query->setProjection('full');
$query->setOrderby('starttime');
$query->setStartMin($three_months_ago);
$query->setStartMax($three_months_from_today);

// Retrieve the event list from the calendar server
try {
    $eventFeed = $service->getCalendarEventFeed($query);
} catch (Zend_Gdata_App_Exception $e) {
    echo "Error: " . $e->getResponse();
}

// Iterate through the list of events, outputting them as an HTML list
print "<ul>\n";
foreach ($eventFeed as $event) {
    print "<li>" . $event->title . "</li>\n";

	$startTime = $event->when->startTime;
    print "<li>" . date("l jS \o\f F Y - h:i A", strtotime( $startTime ) );

	// Google Calendar API's support of timezones is buggy
    print " AST</li>\n";

    print "<li>" . $event->where->valueString . "</li>\n";
}
print "</ul>\n";

Zend Google 数据 API 类的优点之一是在检索到 eventFeed 对象后,摘要的元素和属性可以像 eventFeed 对象的属性一样按层次结构遍历。我认为这样做可以更轻松地阅读处理代码,因为各个元素都是按照类似于 XML 文档中提供的样式来组织的。不同于 DOMNode 的 getAttributeNode("attributeName")->value 方法,也可以按照层次结构的样式从父元素遍历属性。





回页首


用 XPath 和 SimpleXML 进行解析

我认为由于支持使用 XPath 查询 XML 文档,因此 SimpleXML API 是最易于使用的 XML 解析 API 之一。它把 XML 文档封装成已装载的 XML 文档的分层对象属性集。这类似于 DOM 返回可以按层次结构遍历 DOMNode 对象实例的方法。类似于 DOM 的 DOMNode 对象但不同于 Zend 类,需要通过调用 attributes() 方法来检索元素的属性。这将把保存属性的对象作为对象属性返回。清单 8 提供了用 SimpleXML 解析和遍历 Google 数据 API 日历摘要所需的所有逻辑。


清单 8. 用 XPath 和 SimpleXML 解析 Google Calendar 事件摘要
                
    $s = simplexml_load_file($feed); 

    foreach ($s->entry as $item) {
        $gd = $item->children('http://schemas.google.com/g/2005');

        if ($gd->eventStatus->attributes()->value == $confirmed) {
?>
            <font size=+1><b>
                <?php print $item->title; ?>
            </b></font><br>

<?php 
            $startTime = '';
            if ( $gd->when ) {
                $startTime = $gd->when->attributes()->startTime;
            } elseif ( $gd->recurrence ) {
                $startTime = $gd->recurrence->when->attributes()->startTime; 
            } 

            print date("l jS \o\f F Y - h:i A", strtotime( $startTime ) );
            // Google Calendar API's support of timezones is buggy
            print " AST<br>";
?>
            <?php print $gd->where->attributes()->valueString; ?>
            <br><br>

<?php
        }
    } ?>

PHP 的 SimpleXML API 的一个缺点是它的解析速度比 DOM 或 SAX 慢,多达四倍。此缺点源于 SimpleXML 将通过使用 PHP 的动态特性动态创建元素和属性节点。这一点与在类节点中定义元素和属性节点的 Zend Google 数据 API 类形成对照。这使得用 Zend 类逐层遍历节点的速度更快。

SimpleXML 的另一个缺点是支持 XML 名称空间。要从名称空间中检索元素,需要对元素调用 children() 方法。这样做将返回以该名称空间的元素为属性的对象。DOM 和 Zend 类提供了更好的支持,即将所有名称空间的元素表示为可按层次遍历的节点或元素。





回页首


性能注意事项和缓存

讨论 PHP 中的 XML 解析时,我注意到 SimpleXML 可能会比 DOM 或 SAX 解析慢很多倍。我选择 SimpleXML 的原因是它比 SAX 更易于使用并且有助于获得比 DOM 更具有可读性的 XML 解析代码。SimpleXML 动态生成元素和属性节点作为其他节点的属性,有利于获得几乎像 Zend Google 数据 API 类一样可读的节点遍历代码。

但是,本文中提供的代码样例遇到了另外一个问题:它在用户每次访问页面时都要求获得 Google Calendar 事件摘要。如果把这个样例放到 PHP 站点的侧栏中,访问者每次转到任意一个页面 ,代码都将重新下载并解析摘要。考虑到日历可能不会每个小时或者甚至每天都更改,这样做是非常浪费的。如果您的站点非常受欢迎并且每天吸引 1,000 或更多页面点击率(只有 20 至 30 个惟一用户的流行论坛即可轻松达到这个点击率),则针对每次页面点击请求和处理摘要。Google 数据 API 有明确的服务条款,说明不允许执行此类应用。如果不遵守服务条款,Google 可以并且可能将拦截您服务器的 IP 地址。在更糟糕的情况下,Google 可以取消您的帐户。很明显,提倡使用一种更聪明的方法。

有若干个可以实现的策略使样例代码更聪明地在 Google API 服务条款许可范围内运行。这些策略全都涉及缓存脚本所显示的信息以及仅当发生更改时才请求处理整个摘要。深入讨论缓存技术不在本文讨论范围内,但是我将简要讨论缓存技术,让您了解可以改进脚本的方法。

一项技术涉及使用 HTTP 请求报头检查 Google 数据 API 摘要是否已更改。Google 数据服务将根据返回信息中的 <atom:updated> 元素的值设置 Last-Modified 响应报头。脚本在第一次被调用时可以将处理摘要所生成的输出保存到 HTML 文件中。脚本随后可以把 <atom:updated> 时间戳的值存储到数据库记录中。下一次任何用户请求查看事件日历时,客户机都将检索时间戳并把它发送回 If-Modified-Since 请求报头中,以避免在它未发生更改的情况下再次检索摘要。

如果自 If-Modified-Since 标头中指示的时间后内容未发生更改,那么 Google 数据服务将返回一个 304 (Not Modified) HTTP 响应。由于这意味着事件数据未更改,因此脚本随后可以包括 先前生成的 HTML 文件。如果摘要已更改,那么 Google 数据服务将返回 200 (OK) HTTP 响应。在这种情况下,脚本将为 HTML 文件重新生成新内容,将数据库记录设为 <atom:updated> 元素中的新时间戳值,并且包括 新生成的 HTML 文件。

把单个时间戳保存到数据库中是非常多余的,但是 PHP 不像 Microsoft Active Server Page (ASP)、Microsoft ASP.NET、Java servlet 和 JavaServer Page (JSP) 一样支持应用程序级变量,至少出厂时不支持。类似的解决方案是使用共享内存。并不是所有的 PHP 安装都支持共享内存,因为它可能是安全风险隐患。另一种可能的缓存备选方法(尤其当 PHP 应用程序在 Web 服务器集群中运行时)是 memcached,它是最初由 LiveJournal 的创建者开发的集群内存缓存服务,现在已经被 FaceBook 的开发人员全面改进。





回页首


结束语

分享这篇文章……

digg 将这篇文章提交到 Digg
del.icio.us 发布到 del.icio.us
Slashdot 提交到 Slashdot!

Google Calendar 提供了一个集中式 Web 应用程序前端,通过该前端,组织及其管理者可以不受限制地为其成员和公众维护和发布事件日历。Google 数据 API 提供了 Atom 摘要和 Atom 发布协议以使用 Google Calendar 和几乎所有其他 Google 应用程序检索、查询、更新和创建事件和其他信息。

使用 XPath,可以通过查询 Google 数据 API 事件摘要并解析其条目以获得条目元素之间的相关详细信息,自动与 Web 站点显示的最新事件保持同步。虽然 XPath 不是 PHP 工具包中速度最快的 XML API,但是当您手上拥有详细记录的 XML 文档时它是其中最易于使用的。您可以使用缓存来减少 XPath 性能相对较慢的影响。






回页首


下载

描述名字大小下载方法
样例 PHP 代码os-php-xpath.google-calendar-api.zip4KBHTTP
关于下载方法的信息


参考资料

学习

获得产品和技术
  • 使用 IBM 试用软件 改进您的下一个开发项目,这些软件可以通过下载或从 DVD 中获得。

  • 下载 IBM 产品评估版,并开始使用 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。


讨论


关于作者

P.J. Cabrera

P.J. Cabrera 是精通 Ruby on Rails 电子商务及内容管理系统开发的开发人员。他感兴趣的技术包括 Ruby on Rails 和开源脚本语言和框架、灵活的开发实践、网状网络、计算机云、XML 解析和处理技术、设置更多语义 Web 内容的微观格式以及研究针对改进的信息检索、问题解答、文本分类和提取的 Bayesian 过滤和符号化处理的创新应用。访问 pjtrix.com/blawg/ 阅读他的网络博客。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款