Генерация RSS средствами MS SQL Server

Источник: kbyte
Алексей Немиро

RSS уже давно является неотъемлемой частью современного интернета, и, пожалуй, плох тот сайт, который не имеет своей ленты новостей в этом формате. Как известно, RSS по своей сути является обычным XML, со строго определенной структурой и стандартами. MS SQL Server уже давно поддерживает работу с XML, а если так, то программистам вовсе необязательно генерировать RSS-ленты средствами используемых на сайтах языков программирования и технологий, поскольку это можно сделать прямо в базе дынных. 

 

RSS - это формат семейства XML предназначенный для описания лент новостей, анонсов, статей и т.п. За счет строго определенной структуры данных, RSS-ленты легко можно прочитать при помощи программ-агрегаторов, либо через специализированные сайты. На сегодняшний день все популярные интернет-обозреватели имеют встроенную читалку RSS-лент. Впервые идея создания подобного механизма предоставления информации возникла еще в 1995 году, но фактическую реализацию получала лишь в 1999 году компанией Netscape. В те же годы технология RSS была разделена на два разных направления:

  • RDF Site Summary (RSS 0.9/1.0) - формат основанный на XML и RDF, он не получил широкого распространения из-за своей сложности;
  • Really Simple Syndication (RSS 2.0) - собственно, на данный момент это наиболее популярный формат предоставления информации и именно о нем будет идти речь в этой статье.

Позже, в 2006 году в качестве альтернативы RSS, появился формат Atom, основное преимущество которого заключатся в том, что помимо чтения информации, её также можно изменять и удалять. На данный момент Atom активно используется в продуктах компании Google.

 

В рамках этой статьи я не буду рассказывать о спецификации формата RSS 2.0, он достаточно прост и приведенных примеров вполне хватит для создания полноценной ленты новостей. Но если вы захотите познакомиться с RSS 2.0 поближе, то подробную спецификацию можно найти на сайте: http://cyber.law.harvard.edu/rss/rss.html

 

XML и SQL Server

 

Чтение XML

SQL Server, еще с 2000 года, имеет набор стандартных средств для работы с XML. В частности, в базе данных можно хранить данные типа XML, создавать их налету и читать.


Поскольку XML как таковой является строкой, то для того чтобы SQL Server мог работать с XML как с набором данных, нужно ему об этом рассказать. Сделать это можно при помощи системной хранимой процедуры sp_xml_preparedocument. Процедураsp_xml_preparedocument создает представление указанного XML-документа (по сути, таблица) и передает его дескриптор (идентификатор, числовой код). Последующая работа с XML происходит именно через дескриптор, посредствам функции OPENXML. После завершения работы, документ можно удалить при помощи процедуры sp_xml_removedocument, хотя это делать вовсе и не обязательно, поскольку данные и так удалятся по завершению работы текущей сессии. Чтобы было более понятно, о чем идет речь, давайте рассмотрим простой пример чтения XML.

01 DECLARE @h int;
02 DECLARE @data nvarchar(max);
03 SET @data =
04 '<www>
05  <site name="Портал для программистов" url="http://kbyte.ru" />
06  <site name="Поисковая система" url="http://yandex.ru" />
07  <site name="Социальная сеть" url="http://facebook.com" />
08 </www>';
09  
10 exec sp_xml_preparedocument @h OUTPUT, @data;
11  
12 SELECT * FROM OPENXML (@h, '/www/site')
13 WITH ([name] nvarchar(50), [url] nvarchar(100));
14  
15 exec sp_xml_removedocument @h;

Как видите, у нас есть две переменные. Переменная @h имеет числовой тип данных, она предназначена для хранения ссылки на дескриптор представления XML. Переменная @data имеет строкой тип данных, которая служит для передачи XML. Системная процедура sp_xml_preparedocument создает на основе указанных в переменной @data данных представление XML и передает в переменную @h ссылку на это представление.

 

Затем, при помощи инструкции SELECT FROM выводятся данные XML-документа, сформированные в функции OPENXML. Первый параметр функции OPENXML указывает ссылку на дескриптор документа XML, второй параметр указывает ветку, из которой нужно провести выборку данных. Так, в приведенном примере, берутся все элементы site, относящиеся к элементу www. Далее, операторWITH указывает имена атрибутов и выходящий тип данных, которые будут переданы в таблицу. У нас выводятся все атрибуты: nameтипа nvarchar(50), url типа nvarchar(100). Если, например, убрать url, то в выдаче просто не будет такой колонки. Если указать неверный тип данных, то может произойти ошибка. Если указать несуществующее имя, то в выдаче поле будет иметь значение NULL.

 

Функция OPENXML также может принимать и третий параметр - flags, который указывает на тип сопоставления, по умолчанию он имеет нулевое значение - сопоставление по атрибутам. Именно поэтому, в указанном выше примере данные выводятся из XML-атрибутов, а не элементов. Параметр flasg может принимать следующие значения:

0 - значение по умолчанию, как уже было сказано, будет использоваться атрибутная модель сопоставления;
1 - приоритетно используется атрибутная модель, а сопоставление с использованием элементов на втором плане;
2 - сопоставление с использованием элементов;
8 - позволят выбрать метод и приоритет сопоставления.

 

Т.е. если требуется вывести данные из элементов, то нужно использовать опцию 2, как показано в следующем примере.

01 DECLARE @h int;
02 DECLARE @data nvarchar(max);
03 SET @data =
04 '<www>
05  <site>
06  <name>Портал для программистов</name>
08  </site>
09  <site>
10  <name>Поисковая система</name>
12  </site>
13  <site>
14  <name>Социальная сеть</name>
16  </site>
17 </www>';<strong>
18  
19 </strong>exec sp_xml_preparedocument @h OUTPUT, @data;
20  
21 SELECT * FROM OPENXML (@h, '/www/site', 2)
22 WITH ([name] nvarchar(50), [url] nvarchar(100));
23  
24 exec sp_xml_removedocument @h;

Результат выполнения запроса

Рис. 1. Вывод XML в SQL Server в виде таблицы.

 

Как видите, все относительно просто, хотя может быть и еще проще. Начиная с SQL Server 2005 появился тип данных XML, который позволяет обходиться без всего выше описанного. Тип данных XML имеет встроенные методы, которые дают возможность работать с XML без создания дескрипторов.

01 DECLARE @data xml;
02 SET @data =
03 '<www>
04  <site name="Портал для программистов" url="http://kbyte.ru" />
05  <site name="Поисковая система" url="http://yandex.ru" />
06  <site name="Социальная сеть" url="http://facebook.com" />
07 </www>';
08  
09 SELECT
10 n.value('@name', 'nvarchar(50)') AS name,
11 n.value('@url', 'nvarchar(100)') AS url
12 FROM @data.nodes('/www/site') AS node(n)

В этом примере данные берутся напрямую из указанного документа при помощи метода nodes и каждая пачка данных передается в поле n (имя может быть любым) типа node. Значение из конкретного атрибута берется при помощи функции value, которая принимает два параметра. Первый параметр указывает имя XML-сущности, в данном случае, символ "собака" (@) говорит о том, что нужно получить значение из атрибута. Использовать атрибуты достаточно просто, именно поэтому они фигурируют во всех примерах данной статьи. Работа с элементами может показаться несколько сложной для понимания.

01 DECLARE @data xml;
02 SET @data =
03 '<www>
04  <site>
05  <name>Портал для программистов</name>
07  </site>
08  <site>
09  <name>Поисковая система</name>
11  </site>
12  <site>
13  <name>Социальная сеть</name>
15  </site>
16 </www>';
17  
18 SELECT
19 n.value('name[1]', 'nvarchar(50)') AS name,
20 n.value('url[1]', 'nvarchar(50)') AS url
21 FROM @data.nodes('/www/site') AS node(n)

В пример, каждый элемент site теоретически может иметь множество вложенных элементов name и url, т.е. фактически каждый из этих элементов является массивом. Именно поэтому в квадратных скобках указывается индекс элемента, в нашем случае это единица (отсчет начинается с 1).

 

Тип данных XML имеет та же и другие методы, такие как query, exist, modify, но в рамках данной статьи я их рассматривать не буду, если у вас возникнет потребность в использовании этих методов, вам всегда помогут на форуме для программистов.

 

Выдача XML

Создавать XML гораздо проще чем, читать. Во-первых, можно сгенерировать XML в обычной строковой переменной, как показано в следующем примере. Собственно, так можно сделать не только в SQL Server, но и в других СУБД.

01 -- временная таблица, чтобы было на чем показывать пример
02 CREATE TABLE #tmp (id int identity, name nvarchar(50), url nvarchar(100));
03  
04 INSERT INTO #tmp
05 SELECT 'Портал для программистов', 'http://kbyte.ru';
06 INSERT INTO #tmp
07 SELECT 'Поисковая система', 'http://yandex.ru';
08 INSERT INTO #tmp
09 SELECT 'Социальная сеть', 'http://facebook.com';
10  
11 -- основная часть примера
12  
13 DECLARE @xml AS nvarchar(1000);
14 SET @xml = '<www>';
15 SELECT @xml = @xml + '<site name="' + name + '" url="' + url + '" />' FROM #tmp;
16 SET @xml = @xml + '<www>';
17  
18 SELECT @xml;
19  
20 -- удаляем временную таблицу
21 DROP TABLE #tmp;

Во-вторых, в SQL Server 2005 появились средства, которые позволяют буквально парой дополнительных команд превратить любую таблицу в XML. Для выдачи результатов в XML-формате, в инструкции SELECT FROM нужно использовать команду FOR XML. Эта команда умеет генерировать XML в нескольких режимах: RAW, AUTO, EXPLICIT и PATH.

1 SELECT * FROM #tmp FOR XML AUTO;

Рис. 2. Результат автоматического формирования XML.

 

Режим RAW и AUTO самые простые. RAW создает для каждой строки данных XML-элемент, по умолчанию, с именем row, где в качестве атрибутов выступают колонки таблицы. Режим AUTO генерирует XML в зависимости от представленных данных, в нашем случае получается результат совсем далекий от ожидаемого. Более гибкие и, соответственно, сложные режимы это EXPLICIT и PATH.

01 -- временная таблица, чтобы было на чем показывать пример
02 CREATE TABLE #tmp (id int identity, name nvarchar(50), url nvarchar(100));
03  
04 INSERT INTO #tmp
05 SELECT 'Портал для программистов', 'http://kbyte.ru';
06 INSERT INTO #tmp
07 SELECT 'Поисковая система', 'http://yandex.ru';
08 INSERT INTO #tmp
09 SELECT 'Социальная сеть', 'http://facebook.com';
10  
11 -- основная часть примера
12 SELECT name, url FROM #tmp FOR XML PATH('site'), ROOT('www');
13  
14 -- удаляем временную таблицу
15 DROP TABLE #tmp;

Рис. 3. Результат формирования XML в режиме PATH.

 

В этом примере используется режим PATH, первый, и единственный обязательный, параметр которого содержит имя основного элемента - site, в который будут вложены значения полей таблицы. Директива ROOT указывает имя родительской ветки - www. Если требуется изменить имена элементов XML, то это можно сделать стандартными средствами SQL, т.е. путем создания алиасов (синонимов). Символ "собаки" (@) в имени алиса превратит колонку в выдаче в XML-атрибут.

1 SELECT name AS 'the_name', url AS '@address' FROM #tmp FOR XML PATH('site'), ROOT('www');

 

RSS 2.0 и SQL Server

Итак, мы добрались до самой главной части статьи, т.е. к построению данных в формате RSS 2.0. Прежде чем продолжить, я сделаю небольшую табличку новостей, для наглядности.

1 CREATE TABLE news (id_news int identity, title nvarchar(255), category nvarchar(100), main_text nvarchar(max), date_created datetime);
2  
3 INSERT INTO news
4 SELECT 'Kbyte.Ru исполняется 5 лет!', 'Новости сайтов', '13 февраля 2011 года Kbyte.Ru исполняется 5 лет! Пользователей ждут приятные сюрпризы и подарки!', GETDATE();
5 INSERT INTO news
6 SELECT 'Билл Гейтс продает Microsoft', 'Бизнес', 'Основатель корпорации Microsoft Билл Гейтс за год продал 90 миллионов акций компании.', GETDATE();
7 INSERT INTO news
8 SELECT 'Новый и очень хитрый инструмент на FoxTools', 'Новости сайтов', 'На FoxTools.ru появился новый инструмент, который позволяет просматривать HTTP-заголовки вашего запроса к серверу.', GETDATE();

На основе полученных знаний по работе с XML в SQL Server, для формирования RSS 2.0 может получиться следующий код:

01 SELECT
02 -- выбираем только 10 последних новостей
03 TOP 10
04 -- я специально сделал так, на случай,
05 -- если у вас будут колонки называть по-другому
06 -- если имена совпадают с RSS (как у меня), то делать алиасы смысла нет
07 title AS title,
08 category AS category,
09 -- формируем ссылку на новость, примерно так
10 ('http://example.ru/news/show.aspx?id=' + CAST(id_news AS nvarchar)) AS link,
11 ('http://example.ru/news/show.aspx?id=' + CAST(id_news AS nvarchar) + '#comments') AS comments,
12 main_text AS description,
13 -- дата должна быть в формате RFC822
14 CONVERT(varchar, date_created, 126) AS pubDate
15 FROM news
16 -- сортировка по дате
17 ORDER BY date_created DESC
18 -- каждый блок rss должен находиться в элементе item
19 FOR XML PATH('item');

Рис. 4. Первый шаг к формированию RSS 2.0 силами SQL Server.

(кликните по картинке для увеличения)

 

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

01 -- получаем дату обновления ленты
02 DECLARE @lastBuildDate nvarchar(50);
03 SELECT TOP 1 @lastBuildDate = CONVERT(varchar, date_created, 126) FROM news ORDER BY date_created DESC;
04  
05 --
06 SELECT
07 -- добавляем номер версии в родительский элемент rss
08 '2.0' AS '@version',
09 (SELECT
10 -- формируем статичную шапку RSS в соответствии со стандартами
11 -- здесь указаны лишь часто используемые элементы
12 'Генерация RSS средствами MS SQL Server' AS 'title',
13 'http://kbyte.ru' AS 'link',
14 'Пример построения RSS-ленты.' AS 'description',
15 'ru-RU' AS 'language',
16 'My Crazy Hands v.2.7' AS 'generator',
17 -- дату обновления можно получить отдельным вложенным запросом,
18 -- без использования переменной, как в моём случае
19 @lastBuildDate AS 'lastBuildDate',
20  
21 -- формируем тело ленты и передаем в переменную @rss.
22 -- этот код ничем не отличается о ранее показанного,
23 -- просто тут уделаны все комментарии
24 (SELECT TOP 10 title AS title, category AS category,
25 ('http://example.ru/news/show.aspx?id=' + CAST(id_news AS nvarchar)) AS link,
26 ('http://example.ru/news/show.aspx?id=' + CAST(id_news AS nvarchar) + '#comments') AS comments,
27 main_text AS description, CONVERT(varchar, date_created, 126) AS pubDate
28 FROM news ORDER BY date_created DESC
29 -- тут добавлена директива TYPE,
30 -- благодаря ей вложенный запрос возвращает данные
31 -- в формате XML, а не строковом
32 FOR XML PATH('item'), TYPE)
33 FOR XML PATH('channel'), TYPE)
34 FOR XML PATH('rss');

Здесь создано целых три вложенных запроса. Самый нижний формирует тело RSS-ленты. Второй запрос создает ветку channel. Третий - основную ветку rss. В принципе, здесь можно было бы обойтись без третьего запроса, но дело в том, что в элемент rss нужно добавить атрибут с указанием версии RSS, чтобы у пользователей не возникало проблем при работе с RSS-каналом.

 

Все вложенные запросы, благодаря директиве TYPE, возвращают данные в формате XML. Попробуйте убрать эту директиву и увидите, что вместо XML будет обычный текст, с заэнкоденными xml-сущностями.

Рис. 5. Выдача RSS сформированного в SQL Server.

(кликните по картинке для увеличения)

 

Вот собственно и все. В итоге на сайте будет всего несколько строчек кода, который будет делать запрос к SQL Server и выдавать пользователю в браузер готовую RSS-ленту.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=30325