В то время как такие технологии как Ajax и Web 2.0 вносят свой вклад в экспоненциальный рост числа Web-приложений, само содержимое этих приложений играет важную и центральную роль. Как провайдерам, так и потребителям контента требуются эффективные способы публикации/синдикации и подписки/чтения контента, соответственно. Именно в этой сфере простота и мощь RSS делают эту технологию, изобретённую во времена Web 1.0, важной составляющей эры Web 2.0 и ближайшего будущего.
RSS предоставляет контент-провайдерам изящный и широко распространённый формат для кодирования и синдикации периодических изменений контента их сайта. Затем контент-провайдеры делают этот контент доступным всему Интернету или какой-то его части, например, реализуя внутреннюю синдикацию в компании. На другом полюсе находятся потребители контента, которые в поисках необходимой им информации переходят с одного сайта на другой, фильтруя страницу за страницей и даже не начиная осмысливать эту информацию. Чудо под названием RSS устраняет необходимость такого перемещения по страницам, позволяя потребителям получать информацию по любой выбранной категории одним блоком. Кроме того, RSS-каналы позволяют потребителям получать эти информационные блоки по выбранным категориям от любого количества контент-провайдеров.
Как уже говорилось, RSS состоит из двух частей: синдикации и агрегации каналов. Основное преимущество RSS-каналов для потребителей – это возможность их агрегации. Именно об этом и пойдёт речь в статье. Вы узнаете подробности о разработке настраиваемого агрегатора RSS-каналов, отвечающего определённым потребностям потребителей контента.
По мере повсеместного распространения размещённых в Интернете источников информации, перед контент-провайдерами и потребителями контента возникают некоторые проблемы. Основной задачей контент-провайдеров является каким-то образом выделиться на фоне множества конкурентов и привлечь к своему контенту максимальное количество его потребителей. Напротив, основная задача потребителей контента – быстро добраться до информации, распределённой по несметному количеству категорий и предлагаемой множеством контент-провайдеров. На потребителях контента также лежит бремя фильтрации различных отвлекающих внимание объектов, например, анимированной графики или рекламных flash-баннеров, которые могут помешать получению информации, которую они пытаются найти.
Вследствие широкого проникновения Интернета в нашу жизнь, разработчики должны сконцентрироваться на том, чтобы помочь потребителям быстро получать доступ к информации и избежать помех при получении желаемого контента. У контент-провайдеров всё в большей степени возникает необходимость нацеливать поставку динамического контента на несколько различных пользовательских платформ, от Web-браузеров до мобильных устройств. Как упоминалось в начале статьи, RSS снимает многие проблемы, связанные с синдикацией и агрегацией контента. Если вы новичок в RSS, вы можете получить некоторые базовые знания, прочитав статьи об RSS, ссылки на которые приводятся в разделе Ресурсы.
RSS придаёт Интернету такой большой потенциал, что эту технологию можно использовать множеством разных (и подчас неожиданных) способов. Не приходится и говорить, что руководители многих основных компаний, выпускающих программное обеспечение, в последнее время внесли коррективы в свой курс в области Интернета с учётом мощи RSS. (С примером подобного обсуждения можно ознакомиться в ясной и краткой статье Диона Хинчклиффа (Dion Hinchcliffe), основателя и главного редактора уважаемого издания Web 2.0 Journal и AjaxWorld Magazine, в разделе Ресурсы). На рисунке 1 показано, как, по мнению г-на Хинчклиффа, RSS обеспечивает информационную экосистему Web 2.0. Все основные строительные блоки Web 2.0, например, wiki, блог, сервис новостей, сервис агрегации, сервис гибридных приложений и поисковые механизмы используют RSS в качестве своего рода "клея", соединяющего их вместе и воплощающего в реальность идеал Web 2.0 – социальный компьютинг.
Рисунок 1. Роль RSS в Web 2.0 по Хинчклиффу
Сейчас используется несколько версий формата RSS. В RSS версий 0.91, 0.92 и 2.0 применяется специфический XML-формат, в котором описываются RSS-каналы. В RSS версии 1.0 используется несколько отличный от других версий формат XML. Эту небольшую разницу следует принимать во внимание при разработке агрегаторов RSS-каналов. Прочитать об интересной истории RSS можно в одной из статей из раздела Ресурсы.
Осознав важность и полезность формата RSS, рассмотрим подробно разработку настраиваемого агрегатора RSS-каналов. Для этого мы будем использовать язык PHP. В PHP имеется несколько встроенных Web- и XML-функций, которые ускорят разработку. Кроме того, написанный на PHP код можно легко запустить на PHP-сервере, например, на Zend Core, в который входит Zend Framework. Для разработки агрегатора каналов необходимо установить на машину PHP, а также настроить его на работу с пакетами cURL (Client URL) и XML. Я рекомендую установить PHP-сервер Zend Core, он доступен бесплатно, и его легко устанавливать и конфигурировать.
Рассмотрим вкратце основы формата RSS.
В то, что представляет собой RSS сегодня, внесли свой вклад несколько компаний и групп, в том числе Apple, Microsoft®, Netscape, Userland, а также рабочая группа RSS-DEV. Поскольку в процессе принимали участие разные компании, сейчас мы имеем различные версии формата RSS. Это в основном касается RSS версии 1.0 (разработанной RSS-DEV), в которой используется немного другой формат, в отличие от других версий (0.91, 0.92 и 2.0 – у них у всех обратно совместимый формат).
В листинге 1 показан высокоуровневый формат RSS версии 1.0. Важно помнить, что в этом формате корневой элемент называется <rdf> и имеет один элемент <channel> и один или более элементов <item> в качестве дочерних. Помните, что в этом формате элементы <channel> и <item> являются элементами одного уровня.
Листинг 1. Скелет формата RSS версии 1.0
<rdf>
<channel>
.....
.....
</channel>
<item>
<title>My Title</title>
<link>My URL</link>
<description>My Description</description>
.....
.....
</item>
</rdf>
|
В листинге 2 показан высокоуровневый формат RSS версий 0.91, 0.92 и 2.0. Можно видеть, что в этом формате корневой элемент называется <rss>, а не <rdf>. Корневой элемент <rss> имеет только один дочерний элемент под названием <channel>, а все элементы <item> являются потомками элемента <channel>. В этом состоит существенное различие с RSS 1.0. Эту небольшую разницу следует принимать во внимание при написании кода, анализирующего эти различные форматы RSS. В нашей статье особо важны три потомка элемента <item>. Хорошо, что эти три дочерних элемента одинаковы во всех форматах RSS.
Листинг 2. Скелет формата RSS версий 0.91 и 2.0
<rss>
<channel>
.....
.....
<item>
<title>My Title</title>
<link>My URL</link>
<description>My Description</description>
.....
.....
</item>
</channel>
</rss>
|
Подробные спецификации RSS см. в соответствующих статьях из раздела Ресурсы. В следующих разделах речь пойдёт о компонентах нашего агрегатора RSS-каналов.
Функция RSS, описываемая в данной статье, состоит из следующих компонентов, объясняемых в следующем порядке:
- Программа чтения каналов
- Компонент ввода источников каналов
- Агрегатор каналов
- Компонент вывода результатов каналов
Вместе эти простые компоненты составляют мощную функцию агрегатора RSS-каналов, которую можно интегрировать с другими приложениями многими способами. В следующих разделах мы подробно рассмотрим фрагменты PHP-кода, составляющие эти компоненты. На рисунке 2 показан обзор этих функциональных компонентов.
Рисунок 2. Обзор функциональных компонентов RSS
На рисунке 2 обратите внимание на следующее.
- Компонент чтения каналов выполняет основную работу и занимается в основном получением каналов, предоставляемых данными источниками каналов. Источник каналов – это всего лишь URL-адрес, по которому определённый контент-провайдер периодически публикует содержимое по данной информационной категории. Например, источник каналов может указывать на URL, по которому New York Times публикует все последние заголовки новостей в категории (канале) "бизнес" с помощью основанного на XML формата RSS.
- Компонент агрегатора каналов принимает на вход несколько определённых пользователем источников каналов, а затем вызывает компонент чтения каналов, чтобы получить все элементы канала из каждого настроенного источника каналов.
- Компонент ввода источников каналов определяет и считывает сведения об определённых пользователями источниках каналов. Сведения об источнике каналов могут предоставляться в виде строки, хранящейся в системной памяти, через входной файл или как запись в базе данных.
- Компонент вывода результатов каналов сохраняет объединённые результаты элементов RSS-канала, полученные от определённого источника каналов. Он может сохранять результаты в виде строки в системной памяти, в файл или в таблицу базы данных.
Чтобы упростить нашу работу, мы объединим компоненты ввода источников каналов и вывода результатов каналов, сделав их частью компонента агрегатора каналов. (Набор исходных PHP-файлов для этих компонентов и полный набор документов к ним можно получить в разделе Загрузка). Эти файлы можно извлечь на вашу машину и запустить их с помощью ваших собственных настроенных наборов источников RSS-каналов. Как объяснялось в предыдущем разделе, среда PHP с поддержкой библиотек XML и cURL является обязательным требованием. (Обратитесь к разделу Заключение, из которого можно узнать о множестве способов использования кода для создания агрегатора RSS-каналов).
Теперь мы готовы вникнуть в устройство и работу этих компонентов.
Компонент чтения каналов представляет собой базовый механизм, выполняющий необходимые сетевые коммуникации с источниками канала и анализирует основанные на XML RSS-каналы, возвращаемые источниками канала. Он использует, главным образом, следующие три простых, но мощных функций среды PHP:
-
cURL -
SimpleXML -
PHP-массивы
cURL – это библиотека с отрытым исходным кодом, позволяющая PHP-программе подключаться к удалённому серверу с помощью различных протоколов, например, HTTP, FTP, Telnet и т.д. Она предоставляет набор функций-упаковщиков, выполняющих такие действия как HTTP POST, HTTP GET и HTTP PUT. Чтобы использовать функции cURL, необходимо включить пакет libcurl в среде PHP. PHP-сервер, например Zend Core, предоставляет лёгкий способ включения cURL одним щелчком мыши через программу администрирования Zend Core.
SimpleXML – ещё одно расширение PHP. Как видно из названия, это расширение облегчает работу с XML, будь то чтение XML-документа или запись в него. В PHP версии 5 и выше это расширение включено по умолчанию.
Массивы являются частью базового языка PHP и значительно облегчают работу с коллекциями структур данных. С помощью PHP-массивов мы будем собирать результаты элементов RSS-канала.
Исходный код компонента чтения каналов представляет собой PHP-файл с именем rss_feed_reader.php. Он состоит из следующих трёх специальных функций:
-
get_rss_feeds -
perform_curl_operation -
parse_rss_feed_xml
В следующих абзацах подробно рассматривается код, реализующий эти отдельные функции. Кроме того, исходный код достаточно хорошо документирован, что поможет вам понять логику его работы.
Как показано в листинге 3, get_rss_feeds – это главная функция бизнес-логики, которая вызывается из компонента агрегатора каналов. Эта функция принимает на вход три следующих исходных значения у вызывающей функции:
- имя RSS-провайдера
- URL-адрес RSS-провайдера
- максимальное количество элементов RSS-канала, которое вызывающая функция хочет получить у данного провайдера каналов
Логика этой функции вызывает другую функцию для выполнения сетевых операций cURL, который доставляет содержимое основанного на XML RSS-канала с удалённого URL-адреса провайдера каналов. Он создаёт три массива, каждый из которых содержит коллекцию одного из трёх элементов (title, link, description), которые мы будем собирать с каждого элемента канала в полученном контенте RSS-канала. Из листинга 1 следует, что они являются дочерними элементами внутри элементов <item> в полученном контенте RSS-канала. Далее, логика функции передаёт строку полученного RSS-контента и три массива другой функции, которая анализирует XML-контент и собирает элементы RSS-канала. Если в результате анализа контента RSS-канала мы получаем значение false, это означает, что в полученном контенте RSS-канала была ошибка. В случае ошибки эта функция возвращает пустой массив вызывающей функции. в результате анализа мы получаем значение true, это означает, что элементы канала были проанализированы успешно и в трёх массивах теперь содержится заголовок (title), адрес (URL) и описание (description) каждого полученного элемента канала. Затем эта функция создаёт новый массив результатов, который должен быть возвращён вызывающей функции. В каждом из верхних пяти индексов массива результатов эта функция хранит соответственно имя провайдера, общее количество полученных элементов канала, массивы заголовка, URL и описания. Наконец, она возвращает этот массив результатов вызывающей функции.
Листинг 3. Функция get_rss_feeds
function get_rss_feeds(& $rss_provider_name, & $rss_provider_url,
& $max_rss_items_required) {
// Проверяем, равно ли max_rss_items_required нулю
if ($max_rss_items_required <= 0) {
// Возвращаем пустой массив.
$empty_array = array();
return($empty_array);
} // Конец условия ($max_rss_items_required <= 0)
// Идём далее и извлекаем RSS-контент из данного RSS-провайдера.
$received_rss_feeds = perform_curl_operation($rss_provider_url);
// Иногда XML-данные неправильно кодируются при помощи utf8,
// Это может привести к проблемам при анализе. Кодируем данные правильно.
$received_rss_feeds = utf8_encode($received_rss_feeds);
// Канал пуст?
if (empty($received_rss_feeds)) {
// Возвращаем пустой массив.
$empty_array = array();
return($empty_array);
} // Конец условия (empty($received_rss_feeds))
// Мы получили непустой результат от провайдера RSS-каналов.
// Создаём три пустых массива, содержащих значения из полученных элементов RSS-канала.
$rss_feed_title_array = array();
$rss_feed_url_array = array();
$rss_feed_description_array = array();
// Теперь можно выполнить анализ отдельных элементов RSS-канала.
$parser_result = parse_rss_feed_xml($received_rss_feeds, $max_rss_items_required,
$rss_feed_title_array, $rss_feed_url_array, $rss_feed_description_array);
// Проверяем, удалось ли выполнить анализ XML-контента RSS-канала.
if ($parser_result == true) {
// Мы успешно проанализировали результаты RSS-канала.
// Создаём массив и наполняем его результатами, как
// описывается выше в комментариях по описанию функции.
$result_array = array();
// Отправляем имя RSS-провайдера.
$result_array[0] = $rss_provider_name;
// Сообщаем, сколько элементов RSS-канала возвращается.
$result_array[1] = sizeof($rss_feed_title_array);
// Отправляем массив, содержащий различные заголовки RSS-канала.
$result_array[2] = $rss_feed_title_array;
// Отправляем массив, содержащий различные URL-адреса RSS-канала.
$result_array[3] = $rss_feed_url_array;
// Отправляем массив, содержащий различные описания RSS-канала.
$result_array[4] = $rss_feed_description_array;
// Теперь возвращаем массив результатов.
return($result_array);
} else {
// Не удалось проанализировать элементы RSS-канала.
// Возвращаем в качестве результата пустой массив.
$empty_array = array();
return($empty_array);
} // Конец условия ($parser_result == true)
} // Конец функции get_rss_feeds
|
Как показано в листинге 4, функция perform_curl_operation выполняет операцию HTTP GET для извлечения содержимого удалённого URL; это происходит так изящно благодаря библиотеке PHP cURL. Данная функция принимает значение удалённого URL в качестве входного аргумента от вызывающей функции. В нашем случае вызывающей является функция get_rss_feeds, о которой мы говорили ранее. Логика функции perform_curl_operation инициализирует новый сеанс cURL. Затем она задаёт различные опции cURL, например, удалённый URL, опцию не включать HTTP-заголовки в ответ, опцию перехода по определённому адресу, если имеется HTTP-заголовок адреса, а также опцию, заставляющую cURL возвращать HTTP-ответ в виде строки из функции curl_exec. Потом она вызывает функцию curl_exec, которая подключается к удалённому URL и извлекает контент RSS-каналов, доступный в этот момент. В ходе этой сетевой операции функция curl_exec будет заблокирована до завершения HTTP-операции. Далее, она закрывает сеанс cURL и возвращает полученный контент RSS-канала вызывающей функции.
Листинг 4. Функция perform_curl_operation function
function perform_curl_operation(& $remote_url) {
$remote_contents = ";
$empty_contents = ";
// Инициализируем сеанс cURL и получаем дескриптор.
$curl_handle = curl_init();
// Открыт ли сеанс cURL?
if ($curl_handle) {
// Задаём необходимые опции CURL.
// Задаём опцию URL.
curl_setopt($curl_handle, CURLOPT_URL, $remote_url);
// Задаём опцию HEADER. В выходных данных нам не нужны заголовки HTTP.
curl_setopt($curl_handle, CURLOPT_HEADER, false);
// Задаём опцию FOLLOWLOCATION. Выполнение будет продолжено,
// если присутствует заголовок адреса.
curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);
// Вместо использования обратного вызова WRITEFUNCTION, мы собираемся получить
// удалённое содержимое как возвращаемое значение функции curl_exec.
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
// Пытаемся извлечь содержимое удалённого URL.
// Эта функция блокируется, пока не будет получено содержимое.
$remote_contents = curl_exec($curl_handle);
// Выполняем очистку CURL.
curl_close($curl_handle);
// Теперь проверяем результат CURL.
if ($remote_contents != false) {
return($remote_contents);
} else {
return($empty_contents);
} // Конец условия ($remote_contents != false)
} else {
// Невозможно инициализировать cURL.
// Без этого ничего не получится.
return($empty_contents);
} // Конец условия ($curl_handle)
} // Конец функции perform_curl_operation
|
Как показано в листинге 5, функция parse_rss_feed_xml отвечает за получение отдельных элементов канала из полученного контента RSS-канала. Эта функция принимает все свои входные аргументы как контрольные значения. Среди её входных аргументов – строка полученного контента RSS-канала, максимальное количество элементов канала, которые желает получить пользователь, а также три массива, где заголовок, URL и описание всех элементов канала будет возвращено вызывающей функции. Если вы ещё не сталкивались с простым в применении расширением PHP SimpleXML, вы узнаете об этом на примере этой функции. В отличие от сложных методик анализа XML, применяемых в других моделях, SimpleXML в PHP позволяет управлять структурой XML как объектной структурой PHP.
Самый первый шаг – просто загрузить строку полученного контента RSS-канала и получить эквивалентную объектную структуру. Прежде чем начинать анализ, нужно определить, закодирован ли полученный контент RSS-канала с помощью RSS версии 1.0 или любой из других версий RSS. Сделать это можно, определив, является ли <item> дочерним элементом корневого элемента, или же дочерним элементом элемента <channel>. Возможно, вам потребуется обратиться к разделу Основы RSS, чтобы вспомнить небольшие различия форматов разных версий RSS. После определения версии формата RSS и подтверждения правильности полученного XML-контента, будет выполняться итерация по всем элементам <item> (в действительности, в данном случае это PHP-объекты) и анализ полей title, link и description. Каждое из этих трёх значений будет добавлено к соответствующим массивам, переданным этой функции как входные аргументы, на которые делается ссылка. После завершения итерации по максимуму необходимых элементов RSS-канала, эта функция возвращает значение true. Если не удалось проанализировать хотя бы один элемент RSS-канала, функция возвращает значение false.
Листинг 5. Функция parse_rss_feed_xml
function parse_rss_feed_xml(& $received_rss_feeds,
& $max_rss_items_required, & $rss_feed_title_array,
& $rss_feed_url_array, & $rss_feed_description_array) {
/*
Мы задействуем возможности PHP SimpleXML API для
анализа этих RSS-каналов, закодированных в формате XML.
Существует несколько версий RSS, а именно 0.91, 0.92, 1.0 и 2.0
Основное различие между этими версиями сводится к одному
из следующих двух форматов.
1) <rss><channel><item>...</item><item>...</item><item>...</item></channel></rss>
2) <rdf><channel>...</channel><item>...</item><item>...</item><item>...</item></rdf>
В формате 1 элементы <item> являются потомками элемента <channel>.
В формате 2 элементы <item> являются прямыми потомками
корневого элемента <rss> или <rdf>.
Другими словами, в формате 2 все элементы <item> имеют
общий родительский элемент <channel>.
В RSS версии 1.0 используется формат 2, в то время как
во всех других версиях – формат 1.
В обоих этих форматах нас интересуют только дочерние элементы между
<item>...</item>.
Наша логика, выполняющая анализ, должна обрабатывать оба эти формата.
*/
// Для начала загрузим строку XML для получения представления объекта SimpleXML.
$xml = simplexml_load_string($received_rss_feeds);
// Это валидный XML-документ.
if ((is_object($xml) == false) || (sizeof($xml) <= 0)) {
// Ошибка отладки XML. Возврат.
return(false);
} // Конец условия ((is_object($xml) == false) ...
// Теперь нужно определить, являются ли элементы <item>
// потомками элемента <channel>, т. е. используется вышеуказанный формат 1 или
// элементы <item> являются прямыми потомками корневого элемента
// <rss> или <rdf>, т. е. используется формат 2.
$obj1 = $xml->item;
if ((is_object($obj1) == false) || (sizeof($obj1) <= 0)) {
// Элементы <item> не являются прямыми потомками корневого элемента документа.
// В данном случае это не формат 2. Следовательно, это формат 1.
// Перемещаемся к элементу <channel>, чтобы он был новым корневым элементом.
$xml = $xml->channel;
} // Конец условия ((is_object($obj1) == false) ...
// Проверяем правильность XML ещё раз.
if ((is_object($xml) == false) || (sizeof($xml) <= 0)) {
// Ошибка отладки XML. Возврат.
return(false);
} // Конец условия ((is_object($xml) == false) ...
// Инициализируем переменную для подсчёта извлечённых элементов <item>.
$count_of_rss_items_retrieved = 0;
// Остаёмся в цикле и собираем сведения из элементов <item>.
foreach ($xml->item as $item) {
// На данном этапе мы обращаемся к элементам <item> по очереди.
// Мы не знаем, сколько всего элементов <item>.
// Прочитаем элементы title, link и description.
$rss_feed_title = trim(strval($item->title));
$rss_feed_url = trim(strval($item->link));
$rss_feed_description = trim(strval($item->description));
// Теперь добавим эти значения к имеющимся ссылкам на массивы.
array_push($rss_feed_title_array, $rss_feed_title);
array_push($rss_feed_url_array, $rss_feed_url);
array_push($rss_feed_description_array, $rss_feed_description);
// Нужно отфильтровать определённое количество элементов <item>
// в соответствии с требованиями пользователя.
Попробуем сделать это сейчас.
$count_of_rss_items_retrieved++;
if ($count_of_rss_items_retrieved >= $max_rss_items_required) {
// Теперь выходим из этого цикла.
break;
} // Конец условия ($count_of_rss_items_retrieved >= $max_rss_items_required)
} // Конец foreach ($xml->item as $item)
if ($count_of_rss_items_retrieved > 0) {
// Наконец-то всё получилось.
return(true);
} else {
// Вся эта трудная работа ни к чему ни привела.
// В следующий раз повезёт больше.
return(false);
} // Конец условия ($count_of_rss_items_retrieved > 0)
} // Конец функции parse_rss_feed_xml
|
Мы завершили изучение основных задач, выполняемых компонентом чтения каналов; переходим к компоненту ввода источников каналов.
Компонент ввода источников каналов
Компонент ввода источников каналов – простейший компонент в нашей системе. Его задача состоит в получении списка источников канала, которые были настроены пользователем. Этот компонент имеет одну функцию, и она вызывается агрегатором каналов в самом начале запуска программы. Как обсуждалось в начале настоящей статьи, информацию об источниках канала можно указывать в структурах данных программы, в таблице БД или в файле. В нашем случае мы предполагаем, что источники канала будут поставляться при помощи XML-файла. Логика компонента ввода источников каналов просто выполняет чтение из файла, имя которого передаётся как входной аргумент функции. Она считывает содержимое XML-файла и возвращает строку вызывающей функции. Как упоминалось ранее, этот компонент находится в том же исходном файле (rss_feed_aggregator.php) вместе с компонентом агрегатора каналов. В листинге 6 показана простая логика, предназначенная для чтения содержимого входного файла источников каналов:
Листинг 6. Функция get_list_of_rss_feed_sources
function get_list_of_rss_feed_sources($input_xml_file) {
// Читаем XML-содержимое из входного файла.
file_exists($input_xml_file) or die("Could not find file " . $input_xml_file);
$xml_string_contents = file_get_contents($input_xml_file);
// Теперь возвращаем XML-содержимое вызывающей функции.
return($xml_string_contents);
} // Конец функции get_list_of_rss_feed_sources
|
Во входном файле источников каналов должен содержаться один или более XML-элементов, предоставляющих информацию об имени провайдера каналов, его URL и максимальном количестве элементов RSS-канала, которое пользователь желает получать от провайдера каналов. В листинге 7 показан формат входного XML-файла источников каналов:
Листинг 7. Формат XML-файла ввода источников каналов
<?xml version="1.0" encoding="UTF-8"?>
<ListOfRssFeedSources>
<!-- Это набор данных для провайдера RSS-каналов 1 -->
<RssFeedSourceInfo>
<rssFeedProviderName>Barron's: Markets</rssFeedProviderName>
<rssFeedProviderUrl>
http://online.barrons.com/xml/rss/3_7517.xml
</rssFeedProviderUrl>
<maximumRssItemsToBeReturned>5</maximumRssItemsToBeReturned>
</RssFeedSourceInfo>
<!-- Здесь можно определить дополнительные элементы провайдера RSS-канала. -->
</ListOfRssFeedSources>
|
Агрегатор каналов представляет собой компонент, упаковывающий компонент чтения каналов с целью достижения главной цели настоящей статьи - создания настраиваемой функции агрегатора RSS-каналов. В нём используется расширение SimpleXML PHP, о котором шла речь в предыдущем разделе. Кроме того, в нём применяется набор специальной логики, выполняющей агрегацию RSS-каналов. Исходный код этого компонента находится в PHP-файле rss_feed_aggregator.php.
Как показано в листинге 8, компонент агрегатора каналов имеет одну функцию под названием aggregate_rss_feeds. Она принимает в качестве аргумента функции имя входного файла, в котором указаны сведения об источниках RSS-каналов. Если она вызывается без входного аргумента, будет использоваться имя файла по умолчанию – rss_feed_sources.xml. Сначала она вызывает компонент ввода источников каналов для получения сформатированной в виде строки структуры XML, в которой указываются сведения об источниках RSS-каналов. Затем она использует расширение SimpleXML для конвертации сформатированного в виде строки XML-содержимого в объект PHP. Далее, она выполняет итерацию по каждому из имеющихся источников каналов и извлекает имя провайдера каналов, его URL и максимальное количество элементов RSS-канала, которое пользователь желает получать от этого провайдера. Затем она вызывает одну из функций компонента чтения каналов под названием get_rss_feeds, что объяснялось выше. Если результат получения элементов RSS-канала от провайдера будет успешным, то она вызовет компонент вывода результатов каналов. После выполнения итерации по всем источникам каналов эта функция завершает работу, выводя отчёт о процессе агрегации каналов.
Листинг 8. Функция aggregate_rss_feeds
function aggregate_rss_feeds($input_xml_file = RSS_FEED_SOURCES_FILE_NAME) {
// Декларируем переменную для отслеживания текущего
// обрабатываемого источника RSS-каналов.
$feed_source_sequence_number = 0;
// Получаем список источников RSS-каналов.
// В нашем случае мы будем считывать их из входного файла.
$xml_string_contents = get_list_of_rss_feed_sources($input_xml_file);
/*
Мы задействуем возможности PHP SimpleXML API для
анализа этих RSS-каналов, закодированных в формате XML.
*/
// Для начала загрузим строку XML для получения представления объекта SimpleXML.
$xml = simplexml_load_string($xml_string_contents);
// Это валидный XML-документ.
if ($xml == false) {
print ("Sorry. Your RSS feed sources input file contains invalid data.\n");
// Ошибка отладки XML. Возврат.
return;
} // Конец условия ($xml == false)
print ("\n");
/*
Остаёмся в цикле и получаем RSS-каналы из каждого источника.
Корневой элемент документа входного XML-файла – <ListOfRssFeedSources>
Внутри корневого элемента имеется один или более блоков данных, имеющих
следующий формат.
<RssFeedSourceInfo>
<rssFeedProviderName>....</rssFeedProviderName>
<rssFeedProviderUrl>....</rssFeedProviderUrl>
<maximumRssItemsToBeReturned>....</maximumRssItemsToBeReturned>
</RssFeedSourceInfo>
Мы собираемся выполнить итерацию по всем
элементам <RssFeedSourceInfo>.
*/
foreach ($xml->RssFeedSourceInfo as $feed_source) {
// Считываем сведения о следующем источнике каналов из входного файла.
$feed_source_sequence_number++;
$rss_provider_name = trim(strval($feed_source->rssFeedProviderName));
$rss_provider_url = trim(strval($feed_source->rssFeedProviderUrl));
$max_rss_items_required =
trim(strval($feed_source->maximumRssItemsToBeReturned));
print ("Getting RSS feeds from $rss_provider_name ...\n");
// Теперь получаем RSS-каналы из этого источника каналов.
$rss_feeds_result_array =
get_rss_feeds($rss_provider_name, $rss_provider_url, $max_rss_items_required);
if (empty($rss_feeds_result_array) == false) {
// Мы будем выполнять сохранение, только если получим
// один или более результатов RSS-каналов.
// Формат массива результатов объясняется
// в разделе о функции сохранения, о чём речь ниже.
store_rss_feed_results($feed_source_sequence_number,
$rss_feeds_result_array);
} // Конец условия (empty($rss_feeds_result_array) == false)
} // Конец foreach ($xml->RssFeedSourceInfo as $feed_source)
print ("\nFinished getting RSS feeds from $feed_source_sequence_number " .
"feed sources.\n\n");
print ("You can view the received feed items in the .\feed_results directory.\n\n");
print ("Feeds from each active feed source are stored in separate files.\n\n");
print ("These files are named NNN_rss_feed_items.txt, where NNN corresponds to\n" .
"the sequence number of the order in which the feed source is\n" .
"listed in your $input_xml_file file.\n");
} // Конец функции aggregate_rss_feeds
|
Компонент вывода результатов каналов
Компонент вывода результатов каналов используется для хранения результатов RSS-каналов. Этот компонент имеет одну функцию, которая вызывается агрегатором каналов, когда все элементы RSS-канала синтаксически выделяются из полученного контента RSS-канала. Как обсуждалось в начале этой статьи, результаты RSS-каналов можно послать в браузер или другую отдельную программу или сохранить в структуре данных программы, в таблице базы данных или в файле. В нашем случае мы намереваемся хранить результаты каналов, полученные от каждого провайдера RSS-каналов, в отдельном файле. Все файлы результатов хранятся в подкаталоге с именем feed_results. Этот подкаталог будет автоматически создан в каталоге, из которого запускается программа агрегатора каналов.
Как показано в листинге 9, единственная функция компонента вывода результатов каналов под названием store_rss_feed_results, принимает два входных аргумента. Первый аргумент – это порядковый номер файла, который будет использоваться для формирования имени файла результатов. Формат файла результатов – NNN_rss_feed_items.txt, где NNN будет замещён значением первого аргумента функции. Данная функция принимает второй аргумент, который представляет собой вложенный PHP-массив, содержащий все элементы RSS-канала, полученные от определённого провайдера RSS-каналов. Этот массив результатов будет иметь пять элементов, каждый из которых будет содержать одно из следующих значений:
a[0] = имя провайдера RSS-каналов
a[1] = количество элементов канала, полученных от провайдера каналов
a[2] = (rss_feed_title_array) массив заголовков элементов RSS-канала
a[3] = (rss_feed_url_array) массив URL элементов RSS-канала
a[4] = (rss_feed_description_array) массив описаний элементов RSS-канала
Содержимое каждого индекса этих трёх массивов, a[2], a[3] и a[4], взятых вместе, предоставит всю информацию, относящуюся к одному конкретному элементу RSS-канала, присутствующую в полученном RSS XML. Например, объединённая информация из rss_feed_title_array[0], rss_feed_url_array[0] и rss_feed_description_array[0] соответствует первому элементу RSS-канала в полученном XML-контенте RSS.
Сначала логика этой функции создаёт подкаталог feed_results, если его ещё не существует. Далее создаётся файл с уникальным именем для каждого провайдера RSS-каналов. Затем выполняется итерация по массиву результатов и запись в файл со сведениями об элементах RSS-канала для всех элементов канала в массиве результатов. Как вы уже, наверное, знаете, в элемент RSS-канала входит заголовок канала, его URL с подробной информацией и краткое описание. Получив элементы канала, потребители контента могут быстро просмотреть заголовок и описание выбранного канала. Выбрав несколько заинтересовавших их элементов канала, они также могут перейти по URL и получить подробную информацию об этом канале. Таковы преимущества использования агрегации RSS-каналов.
Листинг 9. Функция store_rss_feed_results
function store_rss_feed_results($file_sequence_number, $result_array) {
// Сначала проверяем, существует ли подкаталог с именем "feed_results".
if (file_exists(RSS_FEED_RESULTS_DIRECTORY) == false) {
// Каталог не существует. Создадим его сейчас.
mkdir(RSS_FEED_RESULTS_DIRECTORY);
} // Конец условия (file_exists(RSS_FEED_RESULTS_DIRECTORY) == false)
// Формируем имя файла.
$result_file_name = sprintf("%s/%03d%s", RSS_FEED_RESULTS_DIRECTORY,
$file_sequence_number, RSS_FEED_RESULTS_FILE_NAME_SUFFIX);
// Если файл уже был создан в ходе предыдущих запусков, просто удаляем его.
// Мы перезапишем в него последнюю информацию о канале.
if (file_exists($result_file_name) == true) {
unlink($result_file_name);
}
// Создаём и открываем файл.
$handle = fopen($result_file_name, FILE_CREATE_WRITE_FLAG);
if ($handle == false) {
// Создать файл не удалось. Возврат.
return;
}
// Можно начинать запись полученных RSS-каналов в этот файл.
// Записываем порядковый номер провайдера канала.
$feed_provider_number = FEED_PROVIDER_SEQUENCE_NUMBER .
$file_sequence_number . NEW_LINE;
fwrite($handle, $feed_provider_number);
// Записываем имя провайдера канала.
$feed_provider_name = RSS_FEED_PROVIDER_NAME . $result_array[0] . NEW_LINE;
fwrite($handle, $feed_provider_name);
// Записываем количество полученных элементов канала.
$number_of_received_rss_feeds = RECEIVED_RSS_FEEDS_CNT .
$result_array[1] . NEW_LINE;
fwrite($handle, $number_of_received_rss_feeds);
$rss_feed_title_array = $result_array[2];
$rss_feed_url_array = $result_array[3];
$rss_feed_description_array = $result_array[4];
// Остаёмся в цикле и записываем заголовок, URL и описание.
for($cnt=0; $cnt < sizeof($rss_feed_title_array); $cnt++) {
$feed_item_separator = FEED_ITEM_SEPARATOR_LINE . NEW_LINE;
fwrite($handle, $feed_item_separator);
$feed_item_sequence_number = FEED_ITEM_SEQUENCE_NUMBER .
($cnt+1) . NEW_LINE;
fwrite($handle, $feed_item_sequence_number);
$feed_item_title = FEED_ITEM_TITLE .
$rss_feed_title_array[$cnt] . NEW_LINE;
fwrite($handle, $feed_item_title);
$feed_item_url = FEED_ITEM_URL .
$rss_feed_url_array[$cnt] . NEW_LINE;
fwrite($handle, $feed_item_url);
$feed_item_description = FEED_ITEM_DESCRIPTION . NEW_LINE .
$rss_feed_description_array[$cnt] . NEW_LINE;
fwrite($handle, $feed_item_description);
} // Конец for($cnt=0; $cnt < sizeof($rss_feed_title_array), $cnt++)
$feed_item_separator = FEED_ITEM_SEPARATOR_LINE . NEW_LINE;
fwrite($handle, $feed_item_separator);
fclose($handle);
} // Конец функции store_rss_feed_results
|
На этом мы заканчиваем обзор функциональных компонентов данной программы. Надеемся, что вы стали лучше понимать, как эти компоненты работают вместе. Теперь давайте посмотрим на агрегатор RSS-каналов в работе.
Из раздела Загрузка можно загрузить архив, содержащий следующие файлы:
- rss_feed_aggregator\rss_feed_reader.php
- rss_feed_aggregator\rss_feed_aggregator.php
- rss_feed_aggregator\rss_feed_sources.xml
Распакуйте все три файла на ваш компьютер. Убедитесь, что у вас есть среда PHP, например, среда Zend Core, настроенная на работу cURL и SimpleXML. Один из входящих в состав архива файл (rss_feed_sources.xml) представляет собой пример входного XML-файла источников каналов, содержащий 22 разных источника RSS-каналов. Эти конкретные источники каналов предоставляют RSS-каналы в категории "Бизнес и финансы". При желании можно определить собственный входной XML-файл.
Для запуска агрегатора RSS-каналов нужно использовать следующую команду (обратите внимание, что последний элемент в конце приведённой ниже команды является дополнительным аргументом командной строки):
php -f rss_feed_aggregator.php <Feed sources input XML filename>
|
Как обсуждалось ранее, если не задавать аргумент командной строки, приложение будет использовать входной XML-файл источников каналов по умолчанию (rss_feed_sources.xml). При использовании входного XML-файла источников каналов по умолчанию и при условии, что всё работает правильно, вы должны увидеть результаты, как на рисунке 3.
Рисунок 3. Результаты запуска агрегатора RSS-каналов
В каталоге, из которого запускается агрегатор RSS-каналов, вы должны увидеть новый подкаталог с именем feed_results. В этом подкаталоге должно находиться несколько файлов, содержащих элементы RSS-канала, полученные от каждого из провайдеров RSS-каналов, которые указал пользователь во входном XML-файле источников каналов.
RSS существует уже несколько лет. Её популярность в настоящее время растёт благодаря появлению технологий Web 2.0, например, wiki, блогов, гибридных приложений, порталов социальных сетей и других сервисов агрегации информации. Статья рассказывает о том, насколько прост формат RSS, что делает его отличным выбором для информационной интеграции с другими появляющимися Web-технологиями. Поскольку Интернет – это, прежде всего, информация, RSS продолжит играть главную роль в определении мощных и полезных способов синдикации и распространения этой информации.
В статье представлена информация по разработке агрегатора каналов с помощью полнофункциональных PHP-скриптов. Использовать исходный PHP-код из данной статьи можно разными способами: как автономный инструмент, общую библиотеку для использования с существующей PHP-программой, размещённой на сервере или в виде функции Web-сервиса SOAP/REST, принимающего участие в корпоративной сервис-ориентированной архитектуре (SOA).
Многие великие вещи в жизни (Интернета) очень просты. RSS – просто одна из них. И это не каламбур!
| Описание | Имя | Размер | Метод загрузки |
|---|---|---|---|
| Код агрегатора RSS-каналов | wa-aj-rssphp.zip | 10119 Kб | HTTP |
Научиться
- Оригинал статьи: Build a customizable RSS feed aggregator in PHP (EN).
- Посетите раздел PHP на developerWorks, в котором можно найти исчерпывающие ресурсы по PHP-проектам (EN).
- Узнайте всё, что вы хотели знать об XML, посетив раздел XML на developerWorks.
- Прочтите документацию по PHP API в Руководстве по PHP (EN).
- Узнайте больше о Zend Core (EN).
- Прочтите публикацию Что такое RSS? от O'Reilly Media (EN).
- Ознакомьтесь с историей RSS, рассказанной разработчиком большинства форматов, посетив ресурс История RSS на сайте юридического факультета Гарвардского университета (EN).
- Ещё один взгляд на историю RSS (EN).
- Просмотрите этот пример файла RSS 2.0 на сайте юридического факультета Гарвардского университета (EN).
- Посетите раздел Как использовать RSS сайта UserLand RSS Central (EN).
- Так как Web 2.0 весьма популярен в кругах разработчиков, в разделе Web-разработка сайта developerWorks вы найдёте постоянно обновляющуюся коллекцию ресурсов.
- В блоге Диона Хинчклиффа по Web 2.0 подробно рассматривается множество вопросов, в том числе Роль RSS в Web 2.0 (EN).
- В статье Введение в RSS-каналы (Джеймс Левин, developerWorks, ноябрь 2000 г.) рассматривается формат RSS и некоторые модули Perl с открытым исходным кодом, которые позволят вам без труда работать с RSS-файлами (EN).
- Узнайте больше об RSS, Atom и программах для чтения каналов в статье Введение в синдикацию (Винсент Лауриа, developerWorks, март 2006 г.) (EN).
- В статье Каналы содержимого с RSS 2.0 (Джеймс Левин, developerWorks, декабрь 2003 г.) делается обзор RSS 2.0, рассматриваются новые RSS-разработки и подробно разбирается этот важный формат (EN).
- Статья Реализация синдикации новостей с помощью RSS и Atom (Ин Ин Линь, developerWorks, сентябрь 2006 г.) показывает, как реализовать стандартную архитектуру публикации новостей с помощью форматов синдикации RSS и Atom для облегчения процесса и снижения вероятности человеческой ошибки (EN).
- Ознакомьтесь с методикой, помогающей посетителям вашего сайта читать каналы RSS и Atom и понимать, как они работают, в статье Создание более дружелюбных каналов RSS и Atom (Бенуа Маршал, developerWorks, октябрь 2006 г.) (EN).
- Создание программы для чтения RSS-каналов на Ajax рассматривается в статье Ajax-программа чтения RSS-каналов (Джек Д. Херрингтон, developerWorks, апрель 2007 г.) (EN).
- В руководстве Расширяя границы RSS (Джонатан Левин, developerWorks, декабрь 2007 г.) представлен новаторский подход, в котором свойства ассоциативности известного формата RSS используются для эмуляции функциональности простой реляционной базы данных (EN).
- Читайте Web 2.0 Journal, ведущий в мире ресурс по Web 2.0 (EN).
Получить продукты и технологии
- Загрузите Zend Core с сайта загрузки Zend (EN).
Обсудить
- Примите участие в обсуждении материала на форуме.
- Участвуйте в дискуссионном форуме по Ajax (EN).
Сентил Натан (Senthil Nathan) работает старшим инженером-программистом в IBM T.J. Watson Research Center в Hawthorne, New York. Имеет 21-летний опыт создания программного обеспечения для корпоративных приложений различных типов. В настоящее время в сферу его профессиональных интересов входят технологии SOA, Web-сервисы, Java 2 Platform, Enterprise Edition (J2EE), PHP, Web 2.0 и Ajax.