15 ноября 2007 ~ 13 комментариев

XML + XSLT + CSS + RSS = красивый фид

Что я в последнее время распустил занудно-философские сопли. Пора собраться и писать полезные посты. Сказано-сделано. Предыстория.

Направил фид своего блога через FeedBurner чтобы можно было следить за статистикой. Решил потестить, кликнул на ссылку и… смутился. Передо мной предстала самая обычная веб-страница, но Опера предложила добавить фид в свою читалку.

“Как это?” – подумал я и полез в исходный код страницы. Тут меня ждал еще один сюрприз – я увидел обычный XML-код обычного RSS-потока. Потом наконец догадался, что красивая страничка ни что иное, как XML с файлом стилей XSLT!

К чемо это я? Давно мне не нравилась хрень, которую показывает Опера, если кликнуль по ссылке на RSS-канал на автобегиннере. Вот я и решил поправить это дело.

Итак. Имеем сгенеренный XML-файлик с потоком (для примера всего с одним элементом item):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="windows-1251"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
	<channel xmlns:date="http://exslt.org/dates-and-times" xmlns:exsl="http://exslt.org/common">
		<language>ru</language>
		<title>Название фида</title>
		<link>Ссылка на сайт</link>
		<description>Описание фида</description>
 
		<item>
			<title>Заголовок записи</title>
			<link>Ссылка на запись</link>
			<description>Текст записи</description>
			<guid>http://www.avtobeginner.ru/news/44/</guid>
			<enclosure url="урл картинки к записи (если есть)" />
			<pubDate>дата</pubDate>
		</item>
                 .....
	</channel>
</rss>

Без заданного форматирования это выводится как набор значений тегов без пробелов и переводом строк.

Задача – поправить эту фигню (сделать из XML валидный HTML-файлик). Добавляем строку (вторая по счету):

1
2
3
<?xml version="1.0" encoding="windows-1251"?>
<?xml-stylesheet href="/templates/rss/rss2full.xsl" type="text/xsl" media="screen"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">

В href конечно же пишем путь, где у вас будет лежать файлик rss2full.xsl.

Теперь рассмотрим сам файлик со стилями (rss2full.xsl). По строкам. Пагнали:

1
2
<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

Пояснений не требуется.

1
<xsl:output method="html" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" />

Задаем формат вывода и DOCTYPE результирующего документа.

1
<xsl:variable name="title" select="/rss/channel/title" />

В заголовок страницы записываем строку из тега title, расположенного в теге channel расположенного в теге rss.

1
2
3
4
5
6
7
8
9
<xsl:template match="/">
	<xsl:element name="html">
		<head>
			<title><xsl:value-of select="$title" /></title>
			<link href="/templates/style.css" rel="stylesheet" type="text/css" media="all" />
		</head>
		<xsl:apply-templates select="rss/channel" />
	</xsl:element>
</xsl:template>

Задаем шаблон для всего потока. Формируем хедер: прописываем title и указываем файл стилей (обычный, CSS) – не забываем писать тот путь, который нужен вам.

В конце вызываем обработку тега channel (строка 7).

1
2
3
4
5
6
7
<xsl:template match="channel">
	<body style="padding: 20px;">
		<h1><xsl:value-of select="$title" /></h1>
		<xsl:apply-templates select="item" />
		<p><small>Это RSS-поток с сайта <a href="http://www.avtobeginner.ru/">www.avtobeginner.ru</a></small></p>
	</body>
</xsl:template>

Собственно шаблон для channel. Во-первых, тег body, куда ж без него. Дальше выводим название потока в h1, вызываем обработчик для тегов item и в коней дописываем что-то наподобие копирайта. Можно написать любую отсебятину.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<xsl:template match="item" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<h3>
	<xsl:choose>
		<xsl:when test="guid[@isPermaLink='true' or not(@isPermaLink)]">
			<a href="{normalize-space(guid)}"><xsl:value-of select="title" /></a>
		</xsl:when>
		<xsl:when test="link">
			<a href="{normalize-space(link)}"><xsl:value-of select="title" /></a>
		</xsl:when>
		<xsl:otherwise>
			<xsl:value-of select="title" />
		</xsl:otherwise>
	</xsl:choose>
	</h3>
	<h4><xsl:value-of select="pubDate" /></h4>
	<xsl:value-of select="description" disable-output-escaping="yes" />
	<xsl:if test="count(child::enclosure)=1">
		<p class="mediaenclosure">изображение новости: <a href="{enclosure/@url}"><xsl:value-of select="child::enclosure/@url" /></a></p>
	</xsl:if>
	<br /><br /><br />
</xsl:template>

Шаблон вывода для item‘ов.

Итак, в h3 записываем либо ссылку из тега guid или link, либо просто заголовок элемента. В h4 пихаем дату, вываливаем содержимое тега description.

В конце, если у элемента присутствует тег enclosure – вставляем ссылку на медиа-контент, указанный в нем.

1
</xsl:stylesheet>

Усе. Осталось сваять нужный вам CSS и радоваться.

13 комментариев to “XML + XSLT + CSS + RSS = красивый фид”

  1. Hidden Object 1 сентября 2008 at 21:20 Permalink

    Неплохая, а главное – легко усваемая статья ;)
    Только хотелось бы иметь реально работающий .xsl файлик, по типу как у FeedBurner`a.

  2. Knave 2 сентября 2008 at 10:02 Permalink

    Выложу вечером.

  3. Alexander Artemenko 13 ноября 2008 at 3:53 Permalink

    Картинок в статье нет, по клику на ссылку, пишет, что документ не найден.

  4. ffsdmad 2 июня 2009 at 17:22 Permalink

    Теперь догадываешься зачем нужен валидность, откуда берётся валидный HTML/XHTML, и почему невалидный быдло счётчики – говно?

  5. Knave 13 июня 2009 at 22:30 Permalink

    Зачем валидность нужна XML понятно. Зачем она HTML – нет.

  6. ffsdmad 15 июня 2009 at 1:34 Permalink

    например вот
    xsltproc твойщаблон.xsl http://валидныйсайт
    и вообще html проще обрабатывать когда он валидный

  7. ffsdmad 15 июня 2009 at 1:39 Permalink

    /щ/ш

  8. ffsdmad 10 сентября 2009 at 18:49 Permalink

    Куда всё делось то?
    автор, починяй примус

  9. Galchonok 23 сентября 2009 at 13:00 Permalink

    Спасибо большое за статью. Помогла несколько структурировать понимание связки RSS + CSS + XML + XSL. Тру вещь)

    У меня возникла така проблемка:
    1. Формирую файл RSS в формате xml с помощью php.
    2. Однако на локальном хосте страница новостей грузится в обычном виде в стандартной верстке обозревателя.
    3. Если ТОТ же полученный файл *xml сохранить на диск (ff это позволяет) и открыть через обозреватель, то страница подгружается с заданным моим стилем CSS, который гружу к XML через XSL.

    Пробовала через ff и ie. Ситуация одинаковая.
    Сайт на серваке на базе денвера (соответственно связки php+апач+mysql). Библиотека XSL в PHP загружена и работает нормально.

    файл XML формирую в PHP стандартно:

    Буду очень благодарна за любую помощь. Может парсеру нужно каким-то образом указывать на работу с XSL. От чего может зависеть ещё отработка XSL из XML?

  10. Knave 23 сентября 2009 at 19:35 Permalink

    Модули PHP тут совершенно ни причем. XML+XSLT обрабатывает браузер.

    Во-первых, проверьте пути к файлам (xslt, css).
    Во-вторых, заголовки, который отдает денвер.

  11. Galchonok 24 сентября 2009 at 13:31 Permalink

    Спасибо за подсказки…

    1) пути к файлам пробовала задавать по-разному: и относительно и с аштитипи и размещать файлы стилей пробовала как можно более гуманно (и в корневом и путь с “точками и слешами” – всё по очереди) – не помогло.
    2) сам денвер вроде отрабатывает. Я в PHP объявляю с помощью хэдера, что передаю файл формата XML и в связи с этим сама лента отображается нормально браузером. НО в стандартном виде. Если просматривать код страницы в xml (из ff) то сам файл xml формируется верный, в заголовке указан файл для преобразования XSL.

    Подозревала, что у меня не работает xsl библиотека в PHP, но пробовала переустанавливать, прописывала в самом денвере, чтобы работал с xsl.
    Из других вариантов также пробовала:
    3) добавлять в файл htaccess строки
    AddType application/x-httpd-php .xml .xsl
    php_value short_open_tag Off
    4) в файле денвера по работе с апачем пробовала прописывать (apache.pl)
    # Start apache.
    system(“start $exe -w –with-xsl”);
    5) сам PHP работает нормально. – все библиотеки находит (проверяла через php-cgi).
    6) ..в конце концов в файле пхп.ини нет лишних инклудов и т.п.
    7) танцевала с бубном…

    Наткнулась, что у кого-то была проблема подобного рода но тот работает с аспом. Решил проблему, позволив формируемому объекту XML делать свои запросы серверу, дописав: objXML.setProperty “ServerHTTPRequest”, true

    Не подскажите, какие проверки можно ещё сделать, чтобы сузить круг поиска?
    Подозреваю, что это либо вообще невозможно, так как реализации ни у кого не встречала, либо я недопонимаю самых простых вещей.
    Как сделать так, чтобы люди, подписавшиеся на мою ленту, видели её красивой?

    Способ с XML + XSL – это лишь один из нескольких, которые я пробовала. Может есть решение другое? не обязательно простое.
    Спасибо за понимание :)

  12. ffsdmad 9 ноября 2009 at 18:35 Permalink

    Какие у вас странные сложности
    всё что нужно, так это “правильный” http заголовок
    wget –no-proxy –save-header -O /dev/stdout breys.ru/rss/ |head

    Content-Type: application/xml; charset=utf-8

    и xml файл составленный в формате rss

    для работы с xslt удобно, пока не запомните, пользоваться xslt процессором
    даёшь ему на вход 2 файл xsl и xml на выходе получаем, то что запрограммировано в xslt
    например вот так xsltproc breys.ru/www/template/index2.xsl breys.ru/www/tmp/blog.xml
    вроде ещё для FF3 есть плагины
    и не надо ничего усложнять, xslt классная штука, а опытных руках отличная – глядим на яндекс
    зы: все бровзеры одинаково обрабатывают rss, так что ориентируйтесь лучше на роботы типа фрибурнера, тоесть вы кормите ему свой rss а остальное его проблемы

  13. Galchonok 25 ноября 2009 at 10:50 Permalink

    Окей! Огромнейшее спасибо за ответ.
    Действительно, всё гениальное – просто.