Отображение событий Google Calendar на вашем PHP Web-сайте при помощи XPath

XPath и SimpleXML обеспечивают оптимальный баланс между читабельностью и многословием в API XML-анализа

Google Calendar и другие интерактивные приложения-календари предоставляют простые централизованные системы, в которых сообщества пользователей могут поддерживать календари событий, а члены этих сообществ могут получать информацию о предстоящих событиях. Но многие организации предпочитают отображать календари событий на своих собственных порталах, форумах или блогах. Они часто копируют информацию календаря событий из интерактивного приложения на свои Web-сайты, что снижает эффективность централизованного управления событиями. Google Calendar предоставляет API интеграции, который обеспечивает хорошее решение данной проблемы. Узнайте, как использовать XPath для извлечения и отображения данных Google Calendar на вашем PHP Web-сайте.

П.Дж. Кабрера, инженер-программист, Независимый разработчик

П.Дж. Кабрера (P.J. Cabrera) - разработчик, специализирующийся на системах управления контентом и электронной коммерции на Ruby on Rails. Интересуется Ruby on Rails и языками сценариев с открытыми исходными кодами, приемами agile-разработки, ячеистыми сетями, вычислительными системами compute clouds, технологиями XML-анализа и обработки, микроформатами для более семантического Web-контента и исследованиями инновационного использования байесовой фильтрации и символьной обработки для улучшенного извлечения информации, получения ответов на вопросы, категоризации текстовой информации. Посетите его блог по адресу pjtrix.com/blawg/.



20.05.2009

Несколько лет назад, работая внештатным Web-разработчиком, я создал Web-портал на PHP для сообщества владельцев и поклонников определенной модели автомобиля (обычно такие сообщества называются автоклубами, и они очень популярны там, где я живу). За несколько лет до встречи со мной некоторые руководители клуба изучили основы Web-дизайна и самостоятельно создали Web-сайт. Со временем сайт разросся и на нем возникло большое число специальных страниц с информацией о календарных событиях, причем многие из них устарели. Поскольку главной целью сайта было информирование широкой общественности и членов сообщества о мероприятиях, эти страницы были переполнены информацией о календарных событиях.

Со временем эти разрозненные копии календаря событий сообщества вышли из-под контроля. На некоторых страницах в боковых панелях содержались анонсы давно прошедших событий. Даже при нормальном управлении и эффективном Web-дизайне поддержка нескольких копий данных календаря событий на отдельных страницах является затратным по времени и подверженным ошибкам процессом. Вместо того чтобы Web-сайт работал на автоклуб, обнаружилось, что автоклуб работает на свой Web-сайт. Они связались со мной в надежде, что я смогу показать лучший путь.

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

Google Calendar и API данных Google

Такое решение предоставляют приложения интерактивного планирования (например, Google Calendar). Централизуя отображение и управление событиями, пользователи Google Calendar могут совместно использовать и поддерживать данные событий на одном сайте, что устраняет один из множества возможных источников ошибок процесса организации событий. Члены сообщества могут посещать интерактивный календарь, чтобы быть в курсе предстоящих событий и действий, не путаясь в устаревшей информации на разрозненных Web-страницах. По-видимому, интерактивные приложения планирования являются идеальным решением.

Во время разработки Web-сайта при помощи системы управления содержимым Drupal (см. раздел "Ресурсы") я рекомендовал руководителям клуба использовать Google Calendar для поддержки календаря событий. Поначалу идея прижилась, и производительность значительно повысилась, поскольку для обновления созданных мной боковых панелей легко было использовать административный интерфейс Drupal. Но со временем успехи клуба привели к росту числа событий, требовавших уведомления, и редактирование боковой панели событий из простой процедуры превратилось в надоедливую рутинную работу.

Выход из этого затруднительного положения обеспечил API данных Google и его возможности доступа к данным событий Google. API данных Google предоставляет реализацию протокола Atom Publishing Protocol (APP) - API Web-сервисов для чтения и обновления различных типов документов и информации. Существуют также интеграционные API сторонних разработчиков для Microsoft®.NET и языков программирования Java™, Python и PHP, которые инкапсулируют большую часть функциональности API данных Google в наборе объектно-ориентированных классов-оболочек (wrapper classes).

Проведя некоторые исследования, я смог дополнить Drupal-сайт автоклуба постоянно обновляемой боковой панелью "События", в которой отображаются данные о самых последних календарных событиях из учетной записи Google Calendar.


Фид Google Calendar

API данных Google предоставляет много Atom-фидов (feed), содержащих документы и информацию для значительной части Web-сервисов, предлагаемых Google. Google Calendar не является исключением, предоставляя несколько фидов, инкапсулирующих основную часть данных Google Calendar. Имеются фиды с HTTP-аутентификацией и общедоступные. Для извлечения и взаимодействия с аутентифицируемыми фидами HTTP-клиент должен предоставить информацию для аутентификации вместе с GET-запросом HTTP. Аутентифицируемый фид может также обновлять учетную запись Google Calendar при помощи POST-запросов HTTP. HTTP-клиенты, использующие аутентифицируемые фиды, могут добавлять и удалять события, подписываться и отменять подписку на календари, создавать и удалять календари из учетной записи Google.

Google Calendar API предоставляет фиды для доступа ко всем индивидуальным календарям, к которым имеет доступ пользователь из графического пользовательского интерфейса Google Calendar. Сюда относятся календари, принадлежащие пользователю, календари, принадлежащие кому-нибудь еще, но на которые пользователь подписан, и календари, которые пользователь импортировал в режиме "только чтение". Эти календари имеют свои собственные аутентифицируемые частные (private) и общедоступные (public) фиды событий, в которых перечисляются индивидуальные события в календаре. В данной статье внимание концентрируется на общедоступных фидах событий.

Как сделать фид Google Calendar общедоступным

Для создания общедоступного фида событий календаря Google Calendar, которых может быть несколько для одной учетной записи, необходимо войти в Google Calendar, выбрать интересующий вас календарь для обработки и нажать маленькую стрелку вниз возле названия календаря. После нажатия этой стрелки рядом с названием фида появляется меню. Выберите пункт Calendar Settings, обведенный на рисунке 1.

Рисунок 1. Ниспадающее меню Google Calendar для выбранного календаря
Рисунок 1. Ниспадающее меню Google Calendar для выбранного календаря

Затем приложение Google Calendar открывает страницу, на которой можно выбрать различные параметры календаря, например, часовой пояс для событий и название календаря. Важный параметр общедоступных фидов – признак того, является ли сам календарь общедоступным или совместно используемым. Чтобы сделать календарь совместно используемым и доступным через общедоступный фид событий, нажмите ссылку Change sharing settings, показанную на рисунке 2.

Рисунок 2. Изменение видимости календаря
Рисунок 2. Изменение видимости календаря

На странице отобразится вкладка Share this calendar, в которой можно выбрать вариант Share all information on this calendar with everyone. Затем отобразится ряд всплывающих диалоговых окон с запросом о том, действительно ли вы хотите сделать календарь общедоступным. Ответьте Yes и не забудьте сохранить настройки, нажав кнопку Save в нижней части вкладки. Нажмите кнопку Back to Calendar для продолжения добавления событий в календарь.

Проверка фида Google Calendar

Пример фида Google Calendar содержится в файле full.xml исходного кода, ссылка для загрузки которого приведена в разделе "Загрузка". Также предоставлена ссылка на фид-заглушку, используемый в примерах кода в данной статье (см. раздел "Ресурсы").

Фиды событий содержат различные элементы, описывающие событие, например, заголовок события, описание, место и время проведения события. Google Calendar поддерживает также список людей, приглашенных на событие, в виде списка адресов электронной почты, на которые передаются подробности о событии при его обновлении. Если эти адреса электронной почты представляют пользователей Google Calendar, они могут отвечать на приглашение через приложение, и событие также сохраняет их статус присутствия (attendance status). Интеграция с информацией о присутствии выходит за рамки данной статьи, которая посвящена базовой информации о событиях, такой как заголовок события, место и время его проведения. В листинге 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 предоставляет уникальный идентификатор URI (Uniform Resource Identifier), который идентифицирует данное событие в системе Google Calendar. Он не только содержит уникальный номер, но также идентифицирует фид, из которого событие было извлечено. Элементы published и updated используют формат метки времени RFC 3339. Элемент updated указывает последнее время редактирования события, или, в случае нового события, время его создания.

После элементов id, published и updated идут элементы с более читабельной информацией, показанные в листинге 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 состоит из элементов name и email. Автором события является пользователь 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. Атрибут valueString элемента where можно найти в приложении Google Calendar и через API. Google Calendar и API данных Google не поддерживают поиск по конкретному элементу. Вместо этого они выполняют полнотекстовый поиск по строковым элементам, таким как title, author, description и атрибуту valueString элемента where. Как вы увидите далее, исключением является поддержка API данных Google установки интервалов дат начала события для ограничения числа событий, включаемых в результаты запроса.

Ограничение содержимого фида Google Calendar

Чтобы обеспечить возможность извлечения определенных наборов данных, API данных Google поддерживает концепцию параметров http-запроса GET. Используя эти параметры, клиент API данных Google может указать максимальное количество возвращаемых записей (при помощи параметра max-results), элемент, используемый для сортировки записей в фиде (при помощи параметра orderby), и времена начала и конца для возвращаемого диапазона записей (при помощи параметров start-min и start-max). Последние два параметра относятся к диапазону времен начала включаемых в результат событий. start-min указывает начальную дату в диапазоне, а start-max указывает конец диапазона. Оба параметра имеют формат метки времени RFC 3339.

Наконец, можно облегчить синтаксический анализ повторяющихся событий, включив параметр singleevents в строку запроса. Если параметр singleevents имеет значение true, повторяющиеся события указываются в фиде так, как будто они являются отдельными единичными событиями. В противном случае повторяющиеся события включают в себя элемент <gd:recurrence>, который содержит правила повторения в формате iCal. Рассмотрение формата iCal и его синтаксического анализа выходит за рамки данной статьи.

В листинге 4 показан URL фида событий, в который добавлены все параметры запроса. Он отредактирован и разбит на несколько строк для удобства чтения.

Листинг 4. Пример URL фида Google Calendar с параметрами запроса
    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

Синтаксический анализ фида Google Calendar в PHP

Теперь, после обсуждения элементов фида событий Google Calendar и запросов на получение записей об интересующих нас событиях, я рассмотрю способы синтаксического анализа и отображения на странице. PHP предоставляет несколько XML API, которые можно использовать для извлечения списка записей о событиях и получения заголовка, даты, времени и места проведения каждого события. Начнем с API Document Object Model (DOM).

Синтаксический анализ фида с использованием DOM

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

Одним из преимуществ XML DOM API является его скорость. Он загружает весь XML-документ в оперативную память, и извлечение элементов из него полностью происходит в этой памяти. Для больших XML-файлов это малоэффективно, но приемлемо для файлов размером 2 - 3 МБ.

Другим преимуществом XML DOM API является его читабельность. Синтаксический анализ XML с использованием DOM содержит команды для открытия XML-документа и извлечения определенных элементов из него в иерархическом виде. Это очень похоже на английский язык, например, указание PHP "get elements with the 'entry' tag name" (получить элементы с именем тега 'entry'). В листинге 5 приведен пример, поясняющий, что я имею в виду.

Листинг 5. Синтаксический анализ фида событий Google Calendar с использованием DOM API
<?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. Для каждой записи о событии сравнивается атрибут value элемента gd:eventStatusс известным значением для подтвержденных (confirmed) событий. Обратите внимание на то, что префикс gd: указывать не нужно для тега элемента. PHP DOM API работает с пространствами имен, и префикс gd: нужно опускать, иначе анализатор не найдет нужного нам элемента.

Если запись о событии подтверждена, извлекаются элементы title, gd:when и gd:where. Элементы gd:when и gd:where требуют запроса специфических атрибутов, например, startTime и valueString. Мы хотим отобразить даты события в читабельном формате и извлекаем атрибут startTime элемента gd:when для преобразования его в значение long integer, представляющее время. Затем это значение передается в функцию date с указанием обычного формата отображения.

Одним из недостатков DOM API является его детальность. Назначение каждого выражения понятно, поскольку оно соответствует текстовому описанию алгоритма, но код не так лаконичен, как мог бы быть. Методы getElementsByTagName и getAttributeNode для классов DOMNode и DOMDocument существенно увеличивают объем кода.

Синтаксический анализ фида с использованием SAX

Еще одним API XML-анализа, доступным в PHP, является 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. Синтаксический анализ фида событий Google Calendar с использованием SAX API
    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;
        }
    }

В этом коде показаны функции startElement, endElement и textData, ккоторые регистрируются программным механизмом SAX-анализатора в примере сценария. В этом фрагменте кода показана обработка нескольких интересующих нас элементов. Код становится довольно сложным, поскольку XML-элементы в SAX читаются сверху вниз XML-документа. Мы не сможем проверить, имеет ли текущая запись о событии статус confirmed, до тех пор, пока не обработаем некоторые из элементов. Например, элемент gd:eventStatus расположен после элемента title в event. Другим источником сложности является то, что фид имеет элемент title, и каждая запись тоже имеет элемент title. Необходимо устанавливать флажок, чтобы код знал, читается ли элемент title внутри записи. Имеется также элемент gd:when внутри элемента gd:originalEvent в повторяющихся событиях, который не является интересующим нас элементом gd:when. Без такой логики проверки состояния простое соответствие названий элементов выдает неверные результаты.

Данный пример демонстрирует два недостатка SAX API: он намного более многословен, чем DOM API, и в сравнении с примером DOM-кода SAX-анализатор в несколько раз сложнее.

Синтаксический анализ с использованием wrapper-классов Zend Google API

Zend Technologies в сотрудничестве с Google расширила интегрированную среду Zend Framework и предоставила набор объектно-ориентированных классов для PHP, скрывающих множество деталей Atom-фидов API данных Google, обеспечивая в то же время поддержку всей информации данных Google. Эти объектно-ориентированные классы имеют много преимуществ, включая представление различных документов API данных Google в виде абстрактных объектов с методами и простыми параметрами, а также сокрытие деталей Atom-фидов и действий протокола HTTP, таких как запросы GET, PUT и POST. Эти классы также инкапсулируют детали аутентификации пользователей в API данных Google, упрощая написание приложений, поддерживающих все функциональные возможности API данных Google, например, создание и обновление событий из клиентских приложений сторонних разработчиков.

Хотя классы Zend Framework API данных Google упрощают жизнь разработчикам, не очень хорошо знакомых с деталями XML-анализа и протокола HTTP, они имеют свои недостатки. Как показано в листинге 7, код является многословным, поскольку многие конструкторы объектов не принимают параметры. В результате настройку нужно производить через свойства после создания объекта.

Листинг 7. Запрос и обработка фида событий Google Calendar с использованием PHP-классов Zend
<?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);

// Создать экземпляр сервиса Calendar без аутентификации,
// с доступом "только чтение" к общедоступному фиду
$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);

// Извлечь список событий с сервера calendar 
try {
    $eventFeed = $service->getCalendarEventFeed($query);
} catch (Zend_Gdata_App_Exception $e) {
    echo "Error: " . $e->getResponse();
}

// Выполнить итерацию по списку событий, выводя их в виде HTML-списка
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 реализована с ошибками
    print " AST</li>\n";

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

Одним из преимуществ классов Zend API данных Google является то, что после извлечения объекта eventFeed элементы и атрибуты фида можно обходить иерархически как свойства объекта eventFeed. Это, по моему мнению, делает исходный код обработки более читабельным, поскольку различные элементы организованы аналогично их представлению в XML-документе. Атрибуты также можно обходить иерархически, начиная с родительских элементов, в отличие от метода DOMNode getAttributeNode("attributeName")->value.


Синтаксический анализ с использованием XPath и SimpleXML

Я думаю, что SimpleXML API с его поддержкой запроса XML-документов с использованием XPath является одним из самых простых в использовании API XML-анализа. Он инкапсулирует XML-документ как иерархический набор объектных свойств загруженного XML-документа. Это похоже на то, как DOM возвращает экземпляры объекта DOMNode, которые можно обходить иерархически. Аналогично объектам DOMNode DOM и в отличие от классов Zend атрибуты элемента приходится извлекать путем вызова метода attributes(). При этом возвращается объект, хранящий атрибуты как свойства объекта. В листинге 8 представлена вся логика, необходимая для синтаксического анализа и обхода фида API данных Google calendar с использованием SimpleXML.

Листинг 8. Синтаксический анализ фида событий Google Calendar с использованием XPath и SimpleXML
    $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 реализована с ошибками
            print " AST<br>";
?>
            <?php print $gd->where->attributes()->valueString; ?>
            <br><br>

<?php
        }
    } ?>

Недостатком PHP-API SimpleXML является то, что он может быть до четырех раз медленнее, чем DOM или SAX. Это связано с тем, что SimpleXML создает узлы element и attribute "на лету", используя динамическую природу PHP. Сравните это с классами Zend API данных Google, которые определяют узлы element и attribute в коде класса. Это делает иерархический обход узлов с использованием классов Zend более быстрым.

Еще одним недостатком SimpleXML является его поддержка пространств имен XML. Для извлечения элементов из пространства имен необходимо вызывать метод children() элемента. При этом возвращается объект с элементами этого пространства имен как свойствами. DOM и классы Zend обеспечивают лучшую поддержку, представляя все элементы всех пространств имен как отдельные узлы других элементов, которые можно обходить иерархически.


Производительность и кэширование

При обсуждении синтаксического XML-анализа в PHP я упоминал, что SimpleXML может быть в несколько раз медленнее, чем DOM- или SAX-анализ. Основанием моего выбора SimpleXML является то, что он легче в использовании, чем SAX, и позволяет создавать более читабельный код XML-анализа, чем DOM. Генерирование узлов element и attribute в SimpleXML "на лету" как свойств других узлов делает код обхода этих узлов почти таким же читабельным, как и классы Zend API данных Google.

Однако пример кода, включенный в данную статью, страдает от другой проблемы: он запрашивает фид события Google Calendar при каждом заходе пользователя на страницу. Если поместить этот пример в боковую панель PHP-сайта, при каждом перемещении пользователя по страницам сайта код загружает и анализирует фид заново. Это довольно расточительно, учитывая то, что календарь, по всей вероятности, не изменяется ежечасно или даже ежедневно. Если сайт является популярным и имеет 1000 или более посещений в сутки (что легко достигается на популярном форуме уже с 20-30 уникальными пользователями), фид запрашивается и обрабатывается при каждом запросе страниц. API данных Google указывает четкие условия обслуживания, в которых прописана недопустимость такого рода использования. Google может заблокировать IP-адрес вашего сервера (и наверняка сделает это), если вы нарушите условия обслуживания. Еще хуже - Google может удалить вашу учетную запись. Понятно, что требуется более интеллектуальный подход.

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

Одна из методик использует заголовки HTTP-запроса для проверки факта изменения фида API данных Google. Сервисы данных Google устанавливают заголовок ответа Last-Modified, основанный на значении элемента <atom:updated> в возвращаемой информации. При первом вызове сценарий может сохранить сгенерированную при обработке фида информацию в HTML-файле. Затем сценарий может сохранить значение метки времени <atom:updated> в базе данных. При следующем запросе каким-либо пользователем просмотра календаря событий клиентское приложение извлекает метку времени и передает ее обратно в заголовке запроса If-Modified-Since, чтобы избежать повторного извлечения фида, если он не изменился.

Если содержимое не изменилось со времени, указанного в заголовке If-Modified-Since, сервис данных Google возвращает HTTP-ответ 304 (Not Modified). Поскольку это означает, что данные события остались неизмененными, сценарий может включить (include) ранее сгенерированный HTML-файл. Если фид изменился, сервис данных Google возвращает HTTP-ответ 200 (OK). В этом случае сценарий генерирует новое содержимое для HTML-файла, записывает в базу данных новое значение метки времени в элементе <atom:updated> и включает вновь сгенерированный HTML-файл.

Сохранение одной метки времени в базе данных, конечно же, излишество, но PHP не поддерживает переменные уровня приложения, как это делают Microsoft Active Server Pages (ASPs), Microsoft ASP.NET, Java-сервлеты и JavaServer Pages (JSPs), по крайней мере, в стандартной конфигурации. Схожим решением является использование совместно используемой памяти. Не все установки PHP поддерживают совместно используемую память, поскольку она снижает защищенность. Еще одной возможной альтернативой кэшированию, особенно при работе PHP-приложения в кластере Web-серверов, является memcached, кластерный сервис кэширования памяти, первоначально разработанный создателями LiveJournal и значительно улучшенный в настоящее время разработчиками FaceBook.


Заключение

Google Calendar предоставляет внешний интерфейс централизованного Web-приложения, в котором организация и ее руководство могут поддерживать и публиковать календарь событий для своих членов и для широкой общественности в целом. API данных Google предоставляет Atom-фиды и протокол Atom Publishing Protocol для извлечения, запроса, обновления и создания событий и другой информации в Google Calendar и почти всех остальных приложениях Google.

Используя XPath, можно автоматически поддерживать отображение на Web-сайте предстоящих событий в актуальном состоянии путем запроса фидов событий API данных Google и синтаксического анализа его записей для извлечения релевантной информации об их элементах. Хотя XPath не является самым быстрым XML API в наборе инструментальных средств PHP, он является одним из самых простых в использовании, когда работа ведется с XML-документом. Для снижения отрицательного влияния относительно медленной работы XPath можно использовать кэширование.


Загрузка

ОписаниеИмяРазмер
Пример PHP-кодаos-php-xpath.google-calendar-api.zip4KB

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source, XML
ArticleID=390682
ArticleTitle=Отображение событий Google Calendar на вашем PHP Web-сайте при помощи XPath
publish-date=05202009