ROME за один день: разбор и публикация каналов на Java
Готовы ли вы к разбору и публикации каналов RSS и Atom на Java? В данном пошаговом руководстве мы покажем вам как скачать заданный канал, добавить собственное содержимое и опубликовать результаты в другом формате, уложившись в 100 строк кода. (200 строк включая пустые строки и комментарии.)
Учитывая тот факт, что каналы RSS и Atom являются «обычными» XML-документами, вы можете решить, что анализ и создание каналов на Java — простая задача. Для одного конкретного типа RSS это утверждение может быть верным. К сожалению, существует как минимум десять типов каналов RSS и Atom: RSS 0.90, RSS 0.91 Netscape, RSS 0.91 Userland, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, и самый новый формат, Atom 1.0. Кроме того, необходимо поддерживать все существующие пространства имён, такие как Dublin Core, Media и другие. Всё это настолько запутано, что может вызвать у программиста отчаяние. Разработчики на Java, успокойтесь и познакомьтесь с ROME.
О ROME
В данном руководстве мы будем использовать ROME для выполнения сложных задач. ROME — это Java-библиотека с открытым исходным кодом (распространяется под лицензией Apache), спроектированная для облегчения разбора и создания каналов, независимо от их формата. ROME поддерживает все перечисленные форматы каналов RSS и Atom.
ROME — это не просто библиотека с богатыми возможностями, в её послужном списке есть такие сайты как My AOL, CNET Networks и Edmunds.com. На странице wiki Powered By ROME описано, как используется ROME в этих и других приложениях.
Основным принципом работы ROME является анализ любой записи канала RSS или Atom и преобразование её в канонический bean-интерфейс. Благодаря этому, разработчик работает с однотипными компонентами, независимо от их оригинального представления. Даже лучше: ROME упрощает создание нового канала благодаря использованию этих же компонентов. В данном руководстве будет показано как это сделать.
Введение
Чтобы проиллюстрировать использование ROME, мы реализуем несколько возможностей, ставших популярными благодаря сайту FeedBurner, предоставляющему хостинг каналов и статистику для издателей RSS и Atom. Сайт FeedBurner не использует ROME (насколько я знаю), поэтому мы будем имитировать их конечный продукт, а не процесс.
FeedBurner предоставляет сервис называемый FeedFlare, используя который издатели могут добавлять зависимое от контекста примечание к своим каналам RSS или Atom. (Это отличный пример применения паттерна Immediate Action.) Ссылки в примечаниях FeedFlare создаются на основе данных элементов канала и позволяют читателю отправлять ссылку по email, добавлять её в закладки del.icio.us и т.д. На рис. 1 показано как отображается примечание FeedFlare в NewsAlloy:
Рис. 1. FeedBurner добавляет примечание FeedFlare к элементу RSS-канала. Щёлкните для просмотра снимка экрана в натуральную величину.
Чтобы продемонстрировать простоту использования ROME, в данном руководстве будет показано как создать сервис FeedWarmer. Вы будете получать любой выбранный канал RSS x.x или Atom x.x, считывать ключевую информацию о каждом элементе канала, а затем публиковать результат в новом формате.
(Если вы когда-либо интересовались разницей в XML между RSS 1.0, RSS 2.0 и Atom 1.0, то понимаете, что изменение формата канала является непростой задачей. К счастью, всю тяжёлую работу выполняет ROME).
Ключевые ингредиенты
Прежде чем приступить к кодированию, вам будет необходимо скачать несколько вещей. Список ингредиентов, которые понадобятся вам для выполнения сегодняшнего рецепта:
- Java J2SE 1.4 или выше
- ROME 0.8 или выше
- ContentModule 0.3 или выше, это дополнение для ROME, поддерживающее XML-элементы из пространства имён content purl.org.
- JDOM 1.0, для обработки XML
Теперь, когда вы скачали перечисленные ресурсы и ваше окружение готово, приступим к написанию кода.
Создание сервиса FeedWarmer
ROME предоставляет набор интерфейсов, позволяющих получать доступ к данным канала независимо от его формата. При создании класса FeedWarmer мы будем использовать интерфейсы SyndFeed и SyndEntry, чтобы не засорять наш код. Чтобы получить общее представление об используемых классах, держите под рукой документацию по классам ROME.
Давайте начнём с создания базовой структуры класса FeedWarmer . Мы будем расширять данную структуру по мере продвижения по руководству, но вы также можете обращаться к полному исходному коду FeedWarmer.java.
Как показано выше, структура нашей программы довольно простая. Мы добавим детали по мере продвижения, придерживаясь следующего подхода:
- Мы создадим конструктор по умолчанию FeedWarmer() для инициализации переменных экземпляра.
- Основным в данном классе является метод warmFeed() , принимающий в качестве аргументов адрес канала RSS или Atom и желаемый формат выходных данных. Это котнтрольная точка для разбора канала и преобразования его в компонент SyndFeed , модификации компонентов SyndEntry , представляющих каждый элемент канала и возврата результатов в другом формате.
- Метод addFooter() будет использоваться для добавления интерактивного примечания к каждому компоненту SyndEntry . Данные компоненты содержат данные канала и являются представлением RSS-записи или элемента Atom.
- createFooter() является вспомогательным методом, использующим переданные аргументы для создания примечания. В нём добавляется примечание к первоначальному HTML-тексту канала и возвращается результат.
- Наконец, мы используем стандартный метод main() для проверки выполненной работы.
Давайте начнём с конструктора и присваивания значений переменным экземпляра. В библиотеке ROME есть вспомогательные классы для разбора и публикации каналов, поэтому нашему классу потребуются экземпляры классов SyndFeedInput и SyndFeedOutput. Также мы будем использовать модуль ROME для обработки XML-элементов <content:encoded /> . Модули вызываются посредством передачи их схемы, поэтому добавим URL схемы purl.org:
Метод warmFeed()Данный метод является основой программы FeedWarmer. В качестве параметров данному методу передаются URL канала, который мы хотим изменить и строка с форматом, который мы хотим получить на выходе.
Нашей первой задачей является использование экземпляра класса SyncFeedInput для создания компонента SyncFeed из входного потока канала. Библиотека ROME предоставляет класс XmlReader для скачивания канала через HTTP, определения кодировки и создания потока с данными канала.
Теперь, когда мы создали компонент SyndFeed , мы можем установить формат канала в тот, который хотим получить на выходе. Это не оказывает никакого влияния на структуру или содержимое компонента, а сообщает методу SyndFeedOutput в каком формате мы хотим получить XML на выходе.
Вот где проявляется простота использования ROME. Не нужно использовать код XPath или понимать структуру канала, потому что у вас есть интерфейс компонента SyndFeed . Давайте продемонстрируем, что канал был обработан программой FeedWarmer, посредством изменения заголовка канала.
Переходим к менее тривиальным действиям — теперь нам необходимо скачать и изменить каждый элемент RSS (или запись Atom) и добавить к ней примечание. Для этой цели у компонента SyndFeed есть метод getEntries() . Для выполнения задания будем использовать список List компонентов SyndEntry . Мы ещё не закончили писать метод addFooter() , но всё равно добавим его вызов:
Последнее, что необходимо добавить к данному методу — вывод изменённого канала в заданном формате. Это задача для класса SyndFeedOutput , принимающего в качестве аргументов экземпляры классов SyndFeed и Writer . Мы будем использовать класс StringWriter , так как сигнатура метода warmFeed() указывает, что мы должны возвращать значение типа String .
Теперь, когда готова основа класса FeedWarmer, необходимо написать код метода addFooter() .
Метод addFooter()Данному методу передаётся экземпляр класса SyndEntry , представляющий элемент RSS или запись Atom. Нашей основной задачей является определение наилучшего места для вставки нашего HTML-примечания. В одних каналах экранированный HTML-код помещается в элементы <description /> , в других он помещается в блок CDATA внутри элемента <content:encoded /> . Последний вариант является более предпочтительным, поэтому мы ищем данные элементы в первую очередь, и только в том случае, если не находим их, используем экранированный HTML-код из тегов <description /> .
Если сказанное выше, вызывает у вас отторжение, вы не одиноки. Грязный секрет каналов заключается в том, что передовые практики XML часто игнорируются. Но эта проблема выходит за рамки нашей программы.
Как упоминалось выше, мы собираемся использовать модуль ROME ContentModule для определения какие элементы <content:encoded /> мы можем использовать. Данное пространство имён не является частью какой-либо спецификации RSS или Atom, но было добавлено позже для преодоления недостатков экранированного HTML. ROME использует модули для реализации специфики подобных дополнений.
По мере углубления в данный метод, нам потребуется получить значения заголовка и ссылки компонента SyndEntry . Данные значения будут использоваться в методе createFooter() для создания HTML, предоставляемого нашей программой FeedWarmer.
Мы запросили экземпляр класса ContentModule используя пространство имён, определённое как константа в классе. Если полученное значение отлично от null , это означает, что в записи есть как минимум один элемент <content:encoded /> . Мы можем использовать данный модуль для получения кодированных строк из компонента SyndEntry , добавления к каждому примечания и возврата модифицированных кодированных строк обратно в компонент SyndEntry :
Если мы не получили модуль, это означает, что доступен только элемент <description> или его семантический эквивалент. Поскольку их может быть больше одного, мы проходим по каждому и добавляем HTML-примечание. ROME возьмёт на себя экранирование HTML при выводе, если это необходимо.
Этот код завершает метод addFooter() . Теперь нам необходимо написать метод createFooter() , последний метод, выполняющий реальную работу.
Метод createFooter()Мы использовали ROME для выполнения всех сложных задач, поэтому остаётся только создать HTML-примечание, добавляемое к каждой записи SyndEntry . Для имитации некоторых возможностей, предоставляемых проектом, вдохновившим нас на создание программы FeedWarmer, мы добавляем ссылки отправки записи по email, добавления ссылки на неё в del.icio.us и поиска похожих записей на Google Blog Search. В этом коде нет ничего относящегося к ROME, поэтому он самоочевиден.
Предупреждение: не пытайтесь копировать следующий код в Java-редактор. В данном коде используется экранированный HTML, чтобы он корректно отображался в вашем браузере. Вместо этого, используйте код, находящийся в файле FeedWarmer.java, в котором находится неэкранированный HTML.
Это лишь несколько простых примеров того, что можно сделать используя лишь заголовок записи и ссылку на неё. Как только вы поймёте насколько просто получать данные канала используя ROME, появится масса возможностей для использования этих данных при модификации канала.
Метод main()Мы достигли финишной прямой. Напишем простой метод main() , который позволит нам проверить работу программы из командной строки. Первым передаваемым аргументом будет URL любого понравившегося вам канала. Данная версия выводит результаты на консоль в формате RSS 2.0, но её можно легко переделать, чтобы результаты выводились в файл или другой поток вывода.
Пробный запуск
Скомпилируйте FeedWarmer.java и испробуйте ваше творение в деле. В полученном XML-файле у каждой записи должно появиться примечание подобное показанному на рис. 2:
Рис. 2. FeedBurner добавил примечание к элементу RSS-канала. Щёлкните для просмотра снимка экрана в натуральную величину.
Вот пример файла XML, обработанного программой FeedWarmer. Обратите внимание на то, что элемент <description /> остался без изменений, тогда как в конце элемента <content:encoded /> появилось наше примечание:
Куда двигаться дальше
Вы уже убедились, что ROME предоставляет удобный и лёгкий способ разбора и публикации каналов. Но на самом деле данная библиотека поддерживает гораздо больше возможностей, чем было описано в нашей статье. ROME поддерживает вложения, подкасты и многое другое. Для получения дополнительных примеров и руководств посетите страницу ROME Tutorials.
Кроме того, если вы застряли и нуждаетесь в помощи в реализации проекта, использующего ROME, группы пользователей и разработчиков ROME всегда готовы предложить свою помощь. (Открою секрет: я вхожу в команду разработчиков.) Не стесняйтесь зайти на wiki-сайт, подписаться на списки рассылки и принять участие в разработке.