XML+XSLT на примере XML-погоды от gismeteo.ru

Вячеслав Гринин, August 6, 2009

Итак, выполняя свое обещание, публикую статью, посвященную отображению информера погоды gismeteo.ru.

Как вы помните, в прошлый раз в статье Парсинг XML в JavaScript на примере XML-погоды от gismeteo.ru мы написали длинный (в нескольких местах запутанный и непонятный) скрипт на JavaScript, который радостно преобразовывал XML-Данные от ГИС-метео в HTML-формат, который мы и отображали в нашем браузере.

Этот вариант имел ряд недостатков:
1) При отключенном JavaScript в браузере пользователя мы вообще ничего не увидим.
2) Шаблоны, используемые в этом скрипте были настолько запутанные, что иногда и я сам терялся в том, что значит каждый из тегов этого шаблона.
3) И вообще это не модно и несовременно!

Ведь есть технология лучше: XML+XSLT !

Вот выдержка из wikipedia:

XSLT (Extensible Stylesheet Language Transformations) — часть спецификации XSL, задающая язык преобразований XML-документов. Спецификация XSLT является рекомендацией W3C.

При применении таблицы стилей XSLT, состоящей из набора шаблонов, к XML-документу (исходное дерево) образуется конечное дерево, которое может быть другой XML-структурой, HTML-документом или обычным текстом. Правила выбора (и, отчасти, преобразования) данных из исходного дерева пишутся на языке запросов XPath.

XSLT имеет множество различных применений, в основном в области web-программирования и генерации отчётов. Одной из задач, решаемых языком XSLT, является отделение данных от их представления, как часть общей парадигмы MVC (англ. Model-view-controller). Другой стандартной задачей является преобразование XML-документов из одной XML-схемы в другую.
В общем, XSLT – это тоже XML особого вида, главной целью которого является преобразование XML-данных из одного вида в другой.

Собственно, эта статья подразумевается именно как практическое введение в XSLT, а поэтому я сразу приведу результирующий XSLT-шаблон, а затем буду его построчно объяснять. Вот он.

<?xml version="1.0" encoding="UTF-8" ?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="xml" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>

 <!--Шаблон, преобразующий номер дня недели в его текстовое 
представление-->
 <xsl:template name="get-day-of-the-week-abbreviation">
 <xsl:param name="day-of-the-week"/>
 <xsl:choose>
 <xsl:when test="$day-of-the-week = 1">Вс</xsl:when>
 <xsl:when test="$day-of-the-week = 2">Пн</xsl:when>
 <xsl:when test="$day-of-the-week = 3">Вт</xsl:when>
 <xsl:when test="$day-of-the-week = 4">Ср</xsl:when>
 <xsl:when test="$day-of-the-week = 5">Чт</xsl:when>
 <xsl:when test="$day-of-the-week = 6">Пт</xsl:when>
 <xsl:when test="$day-of-the-week = 7">Сб</xsl:when>
 <xsl:otherwise>?</xsl:otherwise>
 </xsl:choose>
 </xsl:template>

 <!--Шаблон, преобразующий порядковый номер месяца в его 
текстовое представление-->
 <xsl:template name="get-month-name">
 <xsl:param name="month"/>
 <xsl:choose>
 <xsl:when test="$month = 1">янв</xsl:when>
 <xsl:when test="$month = 2">фев</xsl:when>
 <xsl:when test="$month = 3">мар</xsl:when>
 <xsl:when test="$month = 4">апр</xsl:when>
 <xsl:when test="$month = 5">май</xsl:when>
 <xsl:when test="$month = 6">июн</xsl:when>
 <xsl:when test="$month = 7">июл</xsl:when>
 <xsl:when test="$month = 8">авг</xsl:when>
 <xsl:when test="$month = 9">сен</xsl:when>
 <xsl:when test="$month = 10">окт</xsl:when>
 <xsl:when test="$month = 11">ноя</xsl:when>
 <xsl:when test="$month = 12">дек</xsl:when>
 <xsl:otherwise>?</xsl:otherwise>
 </xsl:choose>
 </xsl:template>

 <!--Шаблон, показывающий текстовое представление облачности-->
 <xsl:template name="get-cloudiness">
 <xsl:param name="cloudiness"/>
 <xsl:choose>
 <xsl:when test="$cloudiness = 0">ясно</xsl:when>
 <xsl:when test="$cloudiness = 1">малооблачно</xsl:when>
 <xsl:when test="$cloudiness = 2">облачно</xsl:when>
 <xsl:when test="$cloudiness = 3">пасмурно</xsl:when>
 <xsl:otherwise>?</xsl:otherwise>
 </xsl:choose>
 </xsl:template>

 <!--Шаблон, показывающий текстовое представление атмосферных явлений-->
 <xsl:template name="get-precipitation">
 <xsl:param name="precipitation"/>
 <xsl:choose>
 <xsl:when test="$precipitation = 4">дождь</xsl:when>
 <xsl:when test="$precipitation = 5">ливень</xsl:when>
 <xsl:when test="$precipitation = 6">снег</xsl:when>
 <xsl:when test="$precipitation = 7">снег</xsl:when>
 <xsl:when test="$precipitation = 8">гроза</xsl:when>
 <xsl:when test="$precipitation = 10">без осадков</xsl:when>
 <xsl:otherwise>?</xsl:otherwise>
 </xsl:choose>
 </xsl:template>

 <!--Корневой шаблн результирующей страницы-->
 <xsl:template match="/">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 <title>gis meteo informer</title>
 <style type="text/css"></style>
 </head>
 <body>
 <!--Здесь мы выбираем только самый первый(ближайший) прогноз 
под номером 1 -->
 <xsl:apply-templates select="MMWEATHER/*/TOWN/FORECAST[1]"/>
 </body>
 </html>
 </xsl:template>

 <!--Базовый шаблон, отображающий информер-->
 <xsl:template match="MMWEATHER/*/TOWN/FORECAST">
 <div id="informer0">
 <table cellspacing="0" cellpadding="1" width="100%"
 border="0" id="gmtbl5">
 <tr>
 <td width="100%" colspan="3">
 <table cellspacing="0" cellpadding="0" width="100%">
 <tr>
 <td height="20" width="100%" id="gmtdttl5" colspan="3">
 <b><a target="_blank" id="tgmtdttl5" href="http://www.gismeteo.RU/city/daily/4368">Москва</a></b>
 </td>
 </tr>
 </table>
 </td>
 </tr>
 <tr>
 <td width="15%">
 <!--Здесь вставляем шаблон, отображающий атмосферные явления-->
 <xsl:apply-templates select="PHENOMENA"/>
 </td>
 <td width="85%" id="tgmtdtext50">
 <xsl:value-of select="@day"/>
 <!--Далее идет вызов шаблонов, отображающих дату в удобном формате-->
 <xsl:call-template name="get-month-name">
 <xsl:with-param name="month" select="@month" />
 </xsl:call-template> - <xsl:call-template name="get-day-of-the-week-abbreviation">
 <xsl:with-param name="day-of-the-week" select="@weekday" />
 </xsl:call-template><br/>
 <!--Здесь вставляем шаблон, отображающий температуру-->
 <b><xsl:apply-templates select="TEMPERATURE"/></b><br/>
 <a target="_blank" id="lgmtdtext50" href="http://www.gismeteo.RU">
GISMETEO.RU</a>
 </td>
 </tr>
 <tr>
 <td colspan="3" heigth="5"/>
 </tr>
 </table>
 </div>
 </xsl:template>

 <!--Шаблон, отображающий температуру-->
 <xsl:template match="TEMPERATURE">
 <xsl:value-of select="@min"/>..<xsl:value-of select="@max"/> °C
 </xsl:template>

 <!--Шаблон, отображающий атмосферные явления-->
 <xsl:template match="PHENOMENA">
 <xsl:element name="img">
 <xsl:attribute name="height">60</xsl:attribute>
 <xsl:attribute name="width">59</xsl:attribute>
 <xsl:attribute name="alt">
 <xsl:call-template name="get-cloudiness">
 <xsl:with-param name="cloudiness" select="@cloudiness" />
 </xsl:call-template>,
 <xsl:call-template name="get-precipitation">
 <xsl:with-param name="precipitation" select="@precipitation" />
 </xsl:call-template>
 </xsl:attribute>
 <xsl:attribute name="src">http://informer.gismeteo.ru/getcode/html/images/animbg/<xsl:value-of select="@cloudiness"/>.gif</xsl:attribute>
 </xsl:element>
 </xsl:template>

</xsl:stylesheet>

Собственно, строки 1 и 3 – стандартные заголовки для XML-файла. Замечу лишь, что мы используем версию XSLT 1.0. Есть еще и 2.0 версия, но о ней мы поговорим в следующих статьях.

Строка 4 говорит, что результирующий вывод будет HTML.

Строки 7 и 19 задают именованный шаблон get-day-of-the-week-abbreviation, который в будущем мы будем использовать как функцию преобразования номера дня недели в его строковое представление.  В строке 8 задается входно параметр day-of-the-week этого шаблона, нечто вродеаргумента функции. Это собственно сам номер дня недели.

В строках 9 и 18 объявляется секция <xsl:choose>, которая, тестируя некторое условие, вставляет в зависимости от результатов тестирования булева выражения соответствующую строку. Сами проверки заключены в теги <xsl:when></xsl:when> где само тестируемое условие задано аттрибутом test

Собственно, все вплоть до строки 65 – это вспомогательные шаблоны преобразований кодов в их текстовое представление, думаю, что в особых комментариях эти шаблоны не нуждаются.

Строки 68-80, это корневой шаблон, то есть тот шаблон, который будет вызван один раз для корневого элемента исходного XML-файла. Как мы видим, это просто вполне стандартный заголовок HTML-файла. Элемент(ы), для которого(которых) шаблон сработает, задается в атрибуте match шаблона. В нашем случае это “/”. Вообще селекторы (то есть то, что расположено в атрибуте match) пишутся на языке XPath, прочитать про основы которого можно в Википедии, вот здесь. Сам контент результирующей страницы вставляется между тегами <body></body> при помощи конструкции apply-templates.

В строках 83-120 задается базовый шаблон, в котором, собственно можно видеть всю разметку информера. Замечу только, что атрибут atname текущего элемента вставляется в результирующий документ с помощью конструкции <xsl:value-of select=“@atname”/>, как в строке 103, например.

Вызов именованного шаблона осуществляется при помощи такой разметки:

<xsl:call-template name="get-month-name">
<xsl:with-param name="month" select="@month" />
</xsl:call-template>

Как видно, атрибутом name тега xsl:call-template задается имя вызываемого шаблона (помните, мы объявляли их в начале файла?), а внутри секции call-template при помощи тегов xsl:with-param задаются сами подаваемые в шаблон параметры.

А вот еще одна маленькая хитрость. Конструкция:

<xsl:element name="img">
<xsl:attribute name="height">60</xsl:attribute>
<xsl:attribute name="width">59</xsl:attribute>
</xsl:element>

Она позволяет вставить в результирующий документ элемент IMG, с атрибутами width и height, да и в принципе, любой другой элемент, с любыми другими атрибутами. В данном примере будет вставлен элемент <img width=”59″ height=”60″/>

И чуть не забыл! В самом XML-файле необходимо указать шаблон, посредством которого он будет обрабатываться. Это нужно только если вы собираетесь доверить XSLT-парсинг самому браузеру, в котором вы откроете XML-файл. О других методах парсинга расскажу в следующих статьях.

Вот, собственно и все, что я хотел рассказать.
Ссылка на результат работы здесь.
Ссылка на архив с работающим примером – здесь.

В тему:

8комментариев

Все чудесно работает.
Вопрос у меня: как в XML файл попадает ссылка на шаблон, посредством которого он будет обрабатываться?

Максим, September 16, 2009 5:05 pm Reply

Вот первые строки XML-файла. Конкретно во второй строке указан шаблон gis.xsl.
< ?xml version="1.0" encoding="UTF-8"?>
< ?xml-stylesheet type="text/xsl" href="gis.xsl"?>

Вячеслав Гринин, September 17, 2009 12:39 pm Reply

XML файл все время изменяется с сайта gismeteo.
Вопрос: Как в этот файл проставить – ?

Александр, November 9, 2009 9:43 pm Reply

Что Вы имеете в виду?

Вячеслав Гринин, November 9, 2009 10:19 pm Reply

Я хочу чтобы xml файл открывался по ссылке http://informer.gismeteo.ru/xml/34122_1.xml? , но я не знаю как туда вставить ссылку на стиль xsl

Александр, November 9, 2009 10:47 pm Reply

Этот файл генерируется сайтом gismeteo, и в него ничего своего вставить не получится. Да к тому же xml-файл принадлежит домену gismeteo.ru, а файл шаблона будет лежать на другом домене, и у Вас скорее всего такой фокус не выйдет. Чтобы применить к этому xml-файлу свой стиль Вам нужно использовать серверное или клиентское преобразование xml-xslt. Клиентское преобразование (то есть через JavaScript) я описываю в своей статье “Кроссбраузерное XSLT-преобразование в JavaScript” ( http://easy4web.ru/?p=604 ) и в статье “Парсинг XML в JavaScript на примере XML-погоды от gismeteo.ru” ( http://easy4web.ru/?p=393 ). Почитайте, возможно Вам пригодится.

Вячеслав Гринин, November 10, 2009 10:23 am Reply

А можно скопировать себе XML-файл (по расписанию, например) — а потом одеть на него шаблон XSLT ?

Женя, September 27, 2010 1:35 pm Reply

Конечно, можно, если у вас есть нормальный платный PHP-хостинг. Тогда вы сливаете по расписанию в папку на сервере XML-файл, там же храните XSLT-шаблон, а слияние XML+XSLT можете делать при помощи как серверной (PHP, ASP) так и клиентской технологии (JavaScript)

admin, September 27, 2010 3:02 pm Reply
Ваше имя
Ваш email*
Ваш сайт
Текст вашего комментария:

Поиск по блогу:
Подписаться:
Популярные:
Облако тегов:
Разное:
Счетчик: