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

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

Раздел: XML, Оффлайн, 15 ноября 2007 13 комментариев

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

Направил фид своего блога через 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 комментариев

  1. Hidden Object пишет:

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

    1. Knave пишет:

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

  2. Alexander Artemenko пишет:

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

  3. ffsdmad пишет:

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

  4. Knave пишет:

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

  5. ffsdmad пишет:

    например вот
    xsltproc твойщаблон.xsl http://www.likhachev.net/away/ChFHRl4ZHrTR5YHi3ujctIXl2+HpsdrmtbSE5ojksg==/
    и вообще html проще обрабатывать когда он валидный

  6. ffsdmad пишет:

    /щ/ш

  7. ffsdmad пишет:

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

  8. Galchonok пишет:

    Спасибо большое за статью. Помогла несколько структурировать понимание связки 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?

    1. Knave пишет:

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

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

  9. Galchonok пишет:

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

    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 – это лишь один из нескольких, которые я пробовала. Может есть решение другое? не обязательно простое.
    Спасибо за понимание :)

    1. ffsdmad пишет:

      Какие у вас странные сложности
      всё что нужно, так это “правильный” 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 а остальное его проблемы

  10. Galchonok пишет:

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

© 2008–2010 Копилефт и все такое...