Здравствуйте уважаемые Хабровчане. Недавно встретилась задача вывода постраничной навигации с помощью технологии XSLT. После безрезультатных поисков по интернету типовых решений, было принято решение изобрести свой велосипед.
Дано: Номер текущей страницы получаемой из GET запроса. XML файл, состоящий из корневого элемента, в котором множество вложенных однотипных элементов. Для краткости сократим файл до вот такого вида:
Файл данных nav.xml
Надо: Обеспечить постраничную навигацию. Если страница не первая выводилось назад и в начало. Если страница не последняя выводилось далее и в конец. Число элементов на странице, число страниц до и после текущей страницы можно было изменять.
После нескольких часов работы получилось следующее:
Файл преобразования nav.xsl
Получилось длинновато, но не сложно. Таблица разделена на 2 части. В первой выводиться основная HTML разметка и контент в зависимости от страницы. Во второй непосредственно сама навигация.
Шаблон постраничной навигации вызывается по имени и принимает 4 параметра. Это выводимые элементы, номер текущей страницы, количество выводимых элементов на странице и число предыдущих и следующих страниц навигации.
Теперь напишем обработчик на PHP, хотя здесь может быть и любой другой язык.
Файл обработки nav.php
Тут все просто. Подгружаем данные и таблицу стилей. Создаем процессор XSLT. Если есть номер страницы, передаем его в таблицу. Выводим результат преобразования на экран.
Дано: Номер текущей страницы получаемой из GET запроса. XML файл, состоящий из корневого элемента, в котором множество вложенных однотипных элементов. Для краткости сократим файл до вот такого вида:
Файл данных nav.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item id="1"/><item id="2"/><item id="3"/><item id="4"/><item id="5"/><item id="6"/><item id="7"/><item id="8"/><item id="9"/><item id="10"/><item id="11"/><item id="12"/><item id="13"/><item id="14"/><item id="15"/><item id="16"/><item id="17"/><item id="18"/><item id="19"/><item id="20"/><item id="21"/><item id="22"/><item id="23"/><item id="24"/><item id="25"/><item id="26"/><item id="27"/><item id="28"/><item id="29"/><item id="30"/><item id="31"/><item id="32"/><item id="33"/>
</root>
Надо: Обеспечить постраничную навигацию. Если страница не первая выводилось назад и в начало. Если страница не последняя выводилось далее и в конец. Число элементов на странице, число страниц до и после текущей страницы можно было изменять.
После нескольких часов работы получилось следующее:
Файл преобразования nav.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Настройка вывода -->
<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" indent="no" doctype-system="about:legacy-compat"/>
<!-- Номер текущей страницы -->
<xsl:param name="page" select="1"/>
<!-- Основное преобразование -->
<xsl:template match="/">
<!-- Число элементов на странице -->
<xsl:variable name="pageItems" select="5"/>
<!-- Вычисляем текущую страницу -->
<xsl:variable name="pageCurrent">
<xsl:choose>
<!-- Если текущая страница меньше одного -->
<xsl:when test="number($page) < 1">
<xsl:text>1</xsl:text>
</xsl:when>
<!-- Если текущая страница больше общего количества -->
<xsl:when test="number($page) > ceiling(count(/root/*) div $pageItems)">
<xsl:value-of select="ceiling(count(/root/*) div $pageItems)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="number($page)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<html lang="ru">
<head>
<title><xsl:value-of select="concat('Страница № ',$pageCurrent)"/></title>
<!-- Немного стилей для красоты -->
<style>
#nav li{float:left;list-style:none;}
#nav a{text-decoration:none;padding:4px;color:#333}
#nav a.on, #nav a:hover{background:#bbb;}
</style>
</head>
<body>
<h1><xsl:value-of select="concat('Страница № ',$pageCurrent)"/></h1>
<ul>
<xsl:for-each select="/root/*[position() > ($pageCurrent * $pageItems - $pageItems) and position() <= ($pageCurrent * $pageItems)]">
<li><xsl:value-of select="@id"/></li>
</xsl:for-each>
</ul>
<hr/>
<!-- Вызываем шаблон постраничной навигации -->
<xsl:call-template name="pageNav">
<xsl:with-param name="items" select="/root/*"/>
<xsl:with-param name="pageCurrent" select="$page"/>
<xsl:with-param name="pageItems" select="$pageItems"/>
<xsl:with-param name="pageParty" select="4"/>
</xsl:call-template>
</body>
</html>
</xsl:template>
<!-- Шаблон создания постраничной навигации -->
<xsl:template name="pageNav">
<!-- Элементы -->
<xsl:param name="items"/>
<!-- Текущая страница -->
<xsl:param name="pageCurrent"/>
<!-- Число элементов на странице -->
<xsl:param name="pageItems"/>
<!-- Число ссылок назад и вперед -->
<xsl:param name="pageParty"/>
<!-- Всего страниц -->
<xsl:variable name="count" select="ceiling(count($items) div $pageItems)"/>
<ul id="nav">
<!-- В начало и назад -->
<xsl:if test="$pageCurrent > 1">
<li><a href="?page=1"><<</a></li>
<li><a href="?page={$pageCurrent - 1}"><</a></li>
</xsl:if>
<!-- Центральные -->
<xsl:for-each select="$items[(position() - 1) mod $pageItems = 0]">
<xsl:if test="($pageCurrent - $pageParty) <= position() and ($pageCurrent + $pageParty) >= position()">
<li><a href="?page={position()}">
<xsl:if test="$pageCurrent=position()">
<xsl:attribute name="class">on</xsl:attribute>
</xsl:if>
<xsl:value-of select="position()"/>
</a></li>
</xsl:if>
</xsl:for-each>
<!-- Следующая и в конец -->
<xsl:if test="$pageCurrent < $count">
<li><a href="?page={$pageCurrent + 1}">></a> </li>
<li><a href="?page={$count}">>></a></li>
</xsl:if>
</ul>
</xsl:template>
</xsl:stylesheet>
Получилось длинновато, но не сложно. Таблица разделена на 2 части. В первой выводиться основная HTML разметка и контент в зависимости от страницы. Во второй непосредственно сама навигация.
Шаблон постраничной навигации вызывается по имени и принимает 4 параметра. Это выводимые элементы, номер текущей страницы, количество выводимых элементов на странице и число предыдущих и следующих страниц навигации.
Теперь напишем обработчик на PHP, хотя здесь может быть и любой другой язык.
Файл обработки nav.php
<?php
// Подготавливаем данные и таблицу стилей
$data = new DOMDocument('1.0', 'UTF-8');
$data->load('nav.xml');
$view = new DOMDocument('1.0', 'UTF-8');
$view->load('nav.xsl');
// Создаем XSLT процессор
$xsl = new XSLTProcessor();
// Импортируем таблицу стилей
$xsl->importStyleSheet($view);
// Если в запросе есть номер страницы, то передаем ее шаблону
if (isset($_GET['page'])) {
$xsl->setParameter('', 'page', $_GET['page']);
}
// Преобразовываем данные и выводим на экран
echo $xsl->transformToXML($data);
?>
Тут все просто. Подгружаем данные и таблицу стилей. Создаем процессор XSLT. Если есть номер страницы, передаем его в таблицу. Выводим результат преобразования на экран.