В предыдущей главе мы определили места в шаблоне разметки страницы, где, при помощи <xsl:apply-templates select="result" />
, будем выводить результаты преобразования исходных xml-данных полученных в формате UMI Data.
Теперь перед нами стоят следующие задачи:
-
описать правила проверки соответствия шаблонов (см. также ru.wikipedia.org/wiki/XPath)
-
описать сами шаблоны преобразования в рамках поставленных задач
Правило проверки того, что мы находимся на главной странице сайта можно описать следующим образом: в исходном документе UMI Data у тега page
атрибут default
должен быть равен "1". Кроме того, мы должны применять это правило только для apply-templates
в левой колонке, поэтому необходимо указать mode="leftcol"
.
Создадим файл ~/xsltTpls/imports/news.xsl
и добавим туда следующее:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="result[page/@is-default = 1]" mode="leftcol">
<div>
<h2>Новости</h2>
<ul id="news">
</ul>
</div>
</xsl:template>
</xsl:stylesheet>
Для получения списка последних новостей воспользуемся макросом %news lastlist()%: укажем id лент новостей (предположим, что они равны "3" и "4") и количество новостей равное "3".
Замечание
Следует иметь в виду, что указывая в шаблонах id страниц, мы рискуем работоспособностью шаблона в случаях, когда пользователь случайно удалит страницу. Поэтому, в данном случае, мы можем указать URL страницы, однако, тогда мы должны быть уверены в том, что не возникнет необходимость его поменять.
В этом примере мы рассматриваем другие вопросы, поэтому на этой проблеме мы останавливаться не будем.
Для понимания структуры возвращаемых макросом xml-данных, наберите в адресной строке:
http://ваш_сайт/udata/news/lastlist/(3)(4)/notemplate/3
В полученном ответе нас интересует ветвь items
, в которой к каждому элементу item
нам необходимо применить уже свой шаблон — для оформления отдельной новости. Поэтому мы вставляем инструкцию apply-templates
и описываем дополнительный шаблон для item
(для элементов item
главной страницы зададим отдельный mode="news.main.item"
):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="result[page/@is-default = 1]" mode="leftcol">
<div>
<h2>Новости</h2>
<ul id="news">
<xsl:apply-templates select="document('udata://news/lastlist/(3)(4)/notemplate/3')/udata/items" mode="news.main.item" />
</ul>
</div>
</xsl:template>
<xsl:template match="item" mode="news.main.item">
<li>
<div class="date">
</div>
<a href="ссылка на новость">
</a>
<div>
<a href="ссылка на блок комментарии на странице полного текста новости">Комментарии</a>
()
</div>
</li>
</xsl:template>
</xsl:stylesheet>
Рассмотрим недостающие блоки по порядку:
-
Дата публикации новости. У каждого элемента
item
есть атрибутpublish_time
, значением которого является дата публикации новости в UNIX TIMESTAMP. Поэтому воспользуемся макросом %system convertDate()% и выведем результат с помощьюvalue-of
:<xsl:value-of select="document(concat('udata://system/convertDate/', @publish_time, '/(d.m.Y)/'))/udata"/>
-
Ссылка на новость. У каждого элемента
item
есть атрибутlink
, значением которого является ссылка на полный текст новости:<a href="{@link}">
-
Заголовок новости. Выводим содержимое элемента
item
:<xsl:value-of select="." />
-
Ссылка на блок "комментарии" на странице полного текста новости. Воспользуемся ссылкой на якорь, который добавим позднее в шаблон полного текста новости:
<a href="{@link}#comments">Комментарии</a>
-
Количество комментариев. Воспользуемся макросом %comments countComments()%, которому надо передать id текущей новости. Значение id получим из одноименного атрибута элемента
item
и выведем результат работы макроса с помощьюvalue-of
:<xsl:value-of select="document(concat('udata://comments/countComments/', @id))/udata" />
Итоговый шаблон для отображения отдельной новости должен выглядеть следующим образом:
<xsl:template match="item" mode="news.main.item">
<li>
<div class="date">
<xsl:value-of select="document(concat('udata://system/convertDate/', @publish_time, '/(d.m.Y)/'))/udata"/>
</div>
<a href="{@link}">
<xsl:value-of select="." />
</a>
<div>
<a href="{@link}#comments">Комментарии</a>
(<xsl:value-of select="document(concat('udata://comments/countComments/', @id))/udata" />)
</div>
</li>
</xsl:template>
В рамках работы системы UMI.CMS, условие отображения меню из названия лент можно описать очень коротко — отображать меню из лент, если мы получаем страницу от модуля "Новости". Таким образом мы ищем следующее соответствие: в исходном документе UMI Data у тега result
атрибут module
должен быть равен "news". Кроме того, вывод должен осуществляться в левой колонке, поэтому добавляем mode="leftcol"
.
Добавим в файл ~/xsltTpls/imports/news.xsl
следующее:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
...
<xsl:template match="result[@module = 'news']" mode="leftcol">
<div>
<h2>
</h2>
<ul>
</ul>
</div>
</xsl:template>
</xsl:stylesheet>
Рассмотрим недостающие блоки по порядку:
Предположим, что мы хотим вывести в качестве названия поле h1 для этой страницы и id у этой страницы равен "2". Тогда мы можем получить значение поля, воспользовавшись протоколом Upage. Запросим интересующее нас свойство h1, добавив к запросу ".h1" и выведем результат с помощью value-of
:
<xsl:value-of select="document('upage://2.h1')/udata/property/value" />
Структуру возвращаемых xml-данных можно посмотреть, набрав в адресной строке:
http://ваш_сайт/upage/2.h1
Для получения списка лент новостей воспользуемся макросом %news lastlents()%: укажем id страницы раздела, объединяющего ленты ("2"), укажем количество отображаемых названий (предположим, равное "10") и установим значение параметра ignore_paging равное "1" (см. описание макроса).
Для понимания структуры возвращаемых макросом xml-данных, наберите в адресной строке:
http://ваш_сайт/udata/news/lastlents/(2)/notemplate/10/1
В полученном ответе нас интересует ветвь items
, в которой к каждому элементу item
нам необходимо применить уже свой шаблон — для оформления ссылки с названия ленты. Поэтому мы воспользуемся инструкцией apply-templates
и опишем дополнительный шаблон для item
(для этого шаблона зададим отдельный mode="news.lents.menu"
).
Кроме того, нужно предусмотреть варианты "подсветки" текущей ленты, в которой мы в данный момент находимся: либо на странице просмотра ленты, либо на странице просмотра полного текста новости из этой ленты. Для реализации этого вызовем apply-templates
с 2 параметрами:
-
URL открытой страницы — значение
result/page/@link
. Этот параметр понадобится, если мы открыли страницу ленты новостей. -
Id родительской страницы — значение
result/parents/page/@id
. Этот параметр понадобится, если мы открыли страницу полного текста новости.
В итоге добавляем вызов шаблона:
<xsl:apply-templates select="document('udata://news/lastlents/(2)/notemplate/10/1')/udata/items" mode="news.lents.menu">
<xsl:with-param name="thispage-link" select="page/@link"/>
<xsl:with-param name="parentpage-id" select="parents/page/@id"/>
</xsl:apply-templates>
И добавляем сам шаблон, обрабатывающий каждый элемент item
:
<xsl:template match="item" mode="news.lents.menu">
<param name="thispage-link" />
<param name="parentpage-id" />
<li>
<a href="{@link}">
<xsl:if test="@link = $thispage-link or @id = $parentpage-id">
<xsl:attribute name="class">current</xsl:attribute>
</xsl:if>
<xsl:value-of select="." />
</a>
</li>
</xsl:template>
Конструкция <xsl:if>...</xsl:if>
проверяет является ли обрабатываемый элемент лентой, страницу которой мы открыли, либо лентой являющейся родительской для открытой страницы. В этих случаях к тегу <a>
, содержащему элемент списка, добавляется атрибут class="current"
, который мы можем описать по своему усмотрению в CSS.
Сведения о том, кем была открыта страница сайта можно получить, обратившись к элементу user
в полученных xml-данных UMI Data. В случае запроса страницы авторизованным пользователем у элемента user
появляется атрибут status="auth"
.
Добавим соответствующий вызов шаблона со своим собственным mode="dispatches.for-auth"
:
<xsl:apply-templates select="user[@status = 'auth']" mode="dispatches.for-auth" />
Этот шаблон мы вынесем в отдельный файл, который мы уже подключили выше к default.xsl
. Пример создания рабочих шаблонов рассылок описан в отдельной главе данной документации: Подписка на рассылки с сайта средствами XSLT-шаблонизатора.
Страницы лент новостей на сайте — это страницы, отображаемые методом rubric
модуля "Новости". Следовательно, мы можем задать условие применения шаблона таким образом: match="result[@module = 'news'][@method = 'rubric']"
.
Однако, здесь мы должны разделить 2 случая: отображение страницы, объединяющей все ленты (можно назвать ее "Все новости"), и страницы архива конкретной ленты. Для разделения этих случаев напишем два условия:
-
страница "Все новости":
match="result[@module = 'news'][@method = 'rubric']"
. -
архив ленты — убедимся, что это дочерняя страница:
match="result[@module = 'news'][@method = 'rubric'][page/@parentId != '0']"
Для получение списка новостей из данной, или нескольких лент воспользуемся макросом %news lastlist()%, которому в одном случае передадим id данной ленты, а во втором нескольких лент (в нашем случае 2). Обработку вывода всего списка новостей мы будем производить одним шаблоном, который мы вызовем, передав id (один или несколько) в качестве параметра.
Добавим в файл news.xsl
оба условия:
<xsl:template match="result[@module = 'news'][@method = 'rubric']">
<xsl:apply-templates select="page" mode="news.lents">
<xsl:with-param name="lent-id">(3)(4)</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="result[@module = 'news'][@method = 'rubric'][page/@parentId != '0']">
<xsl:apply-templates select="page" mode="news.lents">
<xsl:with-param name="lent-id" select="page/@id" />
</xsl:apply-templates>
</xsl:template>
В первом случае мы передаем в качестве параметра id обеих лент, во втором — id открытой страницы, который мы получаем из атрибута id
элемента page
.
Опишем теперь сам шаблон:
<xsl:template match="page" mode="news.lents">
<h1>
</h1>
<ul>
</ul>
</xsl:template>
Рассмотрим отдельные блоки по порядку:
Заголовок ленты мы можем узнать из переданных xml-данных UMI Data (в этом шаблоне мы обрабатываем ветку page
):
<h1>
<xsl:value-of select="properties/group/property[@name = 'h1']/value" />
</h1>
Атрибуты элемента user
позволяет узнать, каким пользователем открыта данная страница. Поэтому в этом месте вставим следующую инструкцию:
<xsl:apply-templates select="/result/user[not(@status = 'auth')]" mode="dispatches.for-guest" />
Пример составления шаблона можно изучить здесь: Подписка на рассылки с сайта средствами XSLT-шаблонизатора
Для получения списка анонсов вызываем макрос %news lastlist()% c переданным параметром и обрабатываем ветку items
:
<xsl:apply-templates select="$doc-newspage/udata/items" mode="news.lents" />
Теперь нужно описать шаблон обработки результатов макроса. Ситуация практически аналогичная описанной выше в топике «Лента новостей на главной странице сайта». Отличие заключается в том, что здесь нам нужно отобразить также текст анонса новости, которого нет в ответе макроса.
Поэтому добавим шаблон обработки:
<xsl:template match="item" mode="news.lents">
<li>
<div class="date">
<xsl:value-of select="document(concat('udata://system/convertDate/', @publish_time, '/(d.m.Y)/'))/udata"/>
</div>
<a href="{@link}">
<xsl:value-of select="." />
</a>
<div class="anons">
</div>
<div>
<a href="{@link}#comments" class="comments">Комментарии</a>
(<xsl:value-of select="document(concat('udata://comments/countComments/', @id))/udata" />)
</div>
</li>
</xsl:template>
Для получения анонса новости воспользуемся протоколом Upage («Страницы: протокол UPage») — запросим страницу новости, добавив к запросу ".anons," и передадим id обрабатываемого элемента:
<xsl:value-of select="document(concat('upage://', @id, '.anons'))/udata/property/value" disable-output-escaping="yes" />
Если вы хотите, чтобы в анонсах отображалась html-разметка необходимо добавить атрибут disable-output-escaping="yes"
. Если опустить этот атрибут, все html-теги будут экранированы и отображены как текст.
Реализация простейшего постраничного вывода описана в отдельной статье: Постраничный вывод (пейджинг) стредствами XSLT-шаблонизатора.
Правило проверки того, что мы находимся на странице отображения полного текста новости описывается следующим образом — это страница возвращаемая методом item модуля "Новости". Таким образом правило выбора шаблона можно описать следующим образом: match="result[@module = 'news' and @method = 'item']
.
Поэтому добавляем шаблон:
<xsl:template match="result[@module = 'news' and @method = 'item']">
<h1>
</h1>
<div id="new">
<div class="date">
</div>
<div class="content">
</div>
<h3><a name="comments">Комментарии</a></h3>
<h3><a name="addcomment">Добавить комментарий</a></h3>
</div>
</xsl:template>
Рассмотрим недостающие блоки по порядку:
Заголовок новости — это значение элемента value
ветки property
c атрибутом name='h1'
:
<h1>
<xsl:value-of select="page/properties/group/property[@name = 'h1']/value" />
</h1>
Дата публикации доступна в ветке property
с атрибутом name="publish_time"
у элемента value
в значении атрибута unix-timestamp
формата UMI Data. Для вывода ее в нужном нам формате, как и на главной странице сайта и на страницах лент, воспользуемся макросом %system convertDate()%:
<div class="date">
<xsl:value-of select="document(concat('udata://system/convertDate/', page/properties/group/property/value/@unix-timestamp, '/(d.m.Y)/'))/udata"/>
</div>
Полный текст новости — это контент страницы новости. Поэтому мы выведем значение элемента value
ветки property
с атрибутом name="content"
формата UMI Data:
<div class="content">
<xsl:value-of select="page/properties/group/property[@name = 'content']/value" disable-output-escaping="yes"/>
</div>
Здесь также обратите внимание на атрибут disable-output-escaping="yes"
, который в данном случае необходим для отображения html-разметки текста новости.
Здесь надо предусмотреть несколько возможных вариантов, под которые мы напишем отдельные шаблоны:
-
Источника новости может не быть — ничего не выводим (например, если ваш сайт и есть источник).
-
Источник новости может быть ссылкой: либо с названия, либо просто ссылка на сайт-источник.
-
Источник новости может быть просто текстом (оффлайн-источник).
В формате UMI Data есть два элемента, отвечающих за текст ссылки, и за саму ссылку: это элемент property
с атрибутом name="source"
и элемент property
с атрибутом name="source_url"
.
Добавим правило применения шаблонов с условием, что хотя бы один из этих элементов присутствует и со своим собственным mode="news.source"
:
<xsl:apply-templates select="page/properties/group[property[@name = 'source' or @name = 'source_url']]" mode="news.source" />
Теперь опишем шаблоны для каждого случая:
-
Есть текст ссылки и сама ссылка:
<xsl:template match="group[property[@name = 'source'] and property[@name = 'source_url']]" mode="news.source"> <div class="newitem-source"> Источник: <a href="{./property[@name = 'source_url']/value}"> <xsl:value-of select="./property[@name = 'source']/value" /> </a> </div> </xsl:template>
-
Есть текст, но нет ссылки (оффлайн-источник):
<xsl:template match="group[property[@name = 'source'] and not(property[@name = 'source_url'])]" mode="news.source"> <div class="newitem-source"> Источник: <xsl:value-of select="./property[@name = 'source']/value" /> </div> </xsl:template>
-
Есть ссылка, но нет текста ссылки. Тогда продублируем поле — сделаем ссылку текстом:
<xsl:template match="group[not(property[@name = 'source']) and property[@name = 'source_url']]" mode="news.source"> <div class="newitem-source"> Источник: <a href="{property[@name = 'source_url']/value}"> <xsl:value-of select="property[@name = 'source_url']/value" /> </a> </div> </xsl:template>
Для отображения списка комментариев воспользуемся макросом %comments insert()%, которому мы передадим id страницы полного текста новости, полученный из значения одноименного атрибута элемента page
:
<xsl:apply-templates select="document(concat('udata://comments/insert/', page/@id))/udata" mode="comments.list" />
Пример работающих шаблонов отображения списка комментариев можно посмотреть в главе: Комментарии средствами XSLT-шаблонизатора.
Поскольку мы хотим предусмотреть разные варианты форм для зарегистрированных пользователей сайта, и для гостей, то применим инструкцию apply-templates
по ветке user
и передадим в качества параметра id страницы:
<xsl:apply-templates select="user" mode="comments.add">
<xsl:with-param name="page-id" select="page/@id"/>
</xsl:apply-templates>
Описание самих шаблонов отображения форм описано в отдельной главе, посвященной модулю "Комментарии": Комментарии средствами XSLT-шаблонизатора.