Случайная сортировка и вывод случайных элементов в XSLT

в 8:17, , рубрики: php, XML, xslt, метки: , ,

Вступление

В этой статье хочу поделиться с Вами моими попытками создать случайную (хотя уместнее буде сказать псевдослучайную) сортировку средствами XSLT, без использования сторонних приложений и расширений.

Изначально была задача сделать сортировку под PHP-ный XSLT процессор. Но захотелось сделать что-то более уневерсальное.

Опытный образец

Для начала нам понадобиться образец для тестирования сортировки. Не будем заниматься хитросплетениями и напишем просто.

Файл данных data.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="view.xsl"?>
<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"/>
</root>

Генерируем случайности

Для того чтоб что-то случайно отсортировать надо чтоб под рукой было что-нибудь случайное. И не что не подошло лучше, чем функция «generate-id()», которая возвращает уникальный идентификатор элемента в виде строки.

Посмотрим, что у нас получается у разных процессоров которые оказались под рукой.

Файл преобразования view.xml

<?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"/>
	<xsl:template match="/">
		<xsl:for-each select="/root/item">
<xsl:value-of select="generate-id()"/>
		</xsl:for-each>
	</xsl:template>
</xsl:stylesheet>

Результат

PHP FireFox Opera MSXML Safari
id1690783 id0xfd238240 op5275038 IDAKA0MB idp100503080
id1690785 id0xfd2383d0 op5275022 IDAMA0MB idp100502144
id1690788 id0xfd238470 op5275006 IDAOA0MB idp100502072
id1690789 id0xfd2384c0 op5274990 IDAQA0MB idp100502936
id1690787 id0xfd238510 op5274974 IDASA0MB idp100502792
id1690784 id0xfd2640b0 op5274958 IDAUA0MB idp100502648
id1690782 id0xfd2641f0 op5274942 IDAWA0MB idp125378088
id1690779 id0xfd264240 op5274926 IDAYA0MB idp100502504
id1690777 id0xfd264330 op5274910 IDA0A0MB idp125377944
id1690775 id0xfd2643d0 op5274894 IDA2A0MB idp100503224

Глядя на таблицу видно две беды: идентификаторы идут по определенному порядку и каждый XSLT процессор генерирует идентификатор под свой лад. Не могу не написать про мелкомягких, и тут выделились.

Случайная сортировка

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

Файл преобразования view.xml

<?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"/>
	<xsl:template match="/">
		<xsl:for-each select="/root/item">
			<xsl:sort select="translate(generate-id(), 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', '0192834765019283476501928347650192834765019283476501') mod 3.1415" data-type="number"/>
			<xsl:value-of select="@id"/>
		</xsl:for-each>
	</xsl:template>
</xsl:stylesheet>

Основным элементом тут является атрибут «select» элемента «xsl:sort». Итак приступим к разбору: берется уникальный идентификатор текущего элемента (при помощи функции «generate-id()»), у него заменяются все буквенные значения на цифровые (при помощи функции «translate()») и результат делим по модулю на число Пи (почему именно Пи, да что первое в голову пришло).

Хоть и не тянет на идеальное и элегантное решение, но зато работает.

Вывод определенного числа случайных элементов.

Модифицируем таблицу для вывода определенного числа случайных элементов из набора. В этом нам поможет функция определения номера текущего элемента «position()». Выведем 4 случайных элемента.

Файл преобразования view.xml

<?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"/>
	<xsl:template match="/">
		<xsl:for-each select="/root/item">
			<xsl:sort select="translate(generate-id(), 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', '0192834765019283476501928347650192834765019283476501') mod 3.1415" data-type="number"/>
			<xsl:if test="position() &lt; 5">
				<xsl:value-of select="@id"/>
			</xsl:if>
		</xsl:for-each>
	</xsl:template>
</xsl:stylesheet>.

Немного PHP

Так как в начале статьи упоминалось про PHP, то и закончу кодом для преобразования на этом языке.

<?php
$data = new DOMDocument('1.0', 'UTF-8');
$data->load('data.xml');
$view = new DOMDocument('1.0', 'UTF-8');
$view->load('view.xsl');
$xsl = new XSLTProcessor();
$xsl->importStyleSheet($view);
echo $xsl->transformToXML($data);
?>

Автор: parsek

Поделиться

* - обязательные к заполнению поля