Главная » XSLT » Создание обобщенных генераторов наборов узлов

0

Задача

Требуется написать повторно используемые шаблоны для динамической ге­нерации набора узлов.

Решение

Первая обобщенная функция из этой категории генерирует набор узлов путем вызова для значений, последовательность которых определяется функ­цией приращения. Процедура повторяется, пока не будет достигнута верхняя граница:

<xsl:template name="generic:gen-set"> <xsl:param name="x" select="1"/> <xsl:param name="func" select=" ‘identity’ "/>

<xsl:param name="func-param1"

select="$generic:generics[self::generic:func and @name = $func]/ @param1"/>

<xsl:param name="test-func" select=" ‘less-than’ "/> <xsl:param name="test-param1" select="$x + 1"/> <xsl:param name="incr-func" select=" ‘incr’ "/> <xsl:param name="incr-param1" select="1"/> <xsl:param name="i" select="1"/> <xsl:param name="result" select="/.."/>

<!– Проверяем, нужно ли продолжать генерацию –> <xsl:variable name="continue"> <xsl:apply-templates

select="$generic:generics[self::generic:func and @name = $test-func]"> <xsl:with-param name="x" select="$x"/>

<xsl:with-param name="param1" select="$test-param1"/> </xsl:apply-templates> </xsl:variable>

<xsl:choose>

<xsl:when test="string($continue)"> <!– Вычислить func($x) –> <xsl:variable name="f-of-x"> <xsl:apply-templates

select="$generic:generics[self::generic:func and

@name = $func]"> <xsl:with-param name="x" select="$x"/> <xsl:with-param name="i" select="$i"/>

<xsl:with-param name="param1" select="$func-param1"/> </xsl:apply-templates> </xsl:variable>

<!– Вычислить следующее значение $x–> <xsl:variable name="next-x"> <xsl:apply-templates

select="$generic:generics[self::generic:func and

<xsl:with-param name="x" select="$x"/>

<xsl:with-param name="param1" select="$incr-param1"/> </xsl:apply-templates> </xsl:variable>

<xsl:call-template name="generic:gen-set"> <xsl:with-param name="x" select="$next-x"/>

<xsl:with-param name="func" select="$func"/> <xsl:with-param name="func-param1" select="$func-param1"/> <xsl:with-param name="test-func" select="$test-func"/> <xsl:with-param name="test-param1" select="$test-param1"/> <xsl:with-param name="incr-func" select="$incr-func"/> <xsl:with-param name="incr-param1" select="$incr-param1"/> <xsl:with-param name="i" select="$i + 1"/> <xsl:with-param name="result"

select="$result | exslt:node-set($f-of-x)"/> </xsl:call-template> </xsl:when> <xsl:otherwise>

<xsl:apply-templates select="$result" mode="generic:gen-set"/> </xsl:otherwise> </xsl:choose> </xsl:template>

<xsl:template match="node( )" mode="generic:gen-set"> <gen-set>

<xsl:copy-of select="."/> </gen-set> </xsl:template>

Ниже этот шаблон используется для генерации последовательности квадра­тов первых десяти целых чисел:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:generic="http://www.ora.com/XSLTCookbook/namespaces/generic">

<xsl:import href="aggregation.xslt"/>

<xsl:output method="text" />

<xsl:template match="/">

<xsl:call-template name="generic:gen-set"> <xsl:with-param name="x" select="1"/> <xsl:with-param name="func" select=" ‘square’ "/> <xsl:with-param name="incr-param1" select="1"/> <xsl:with-param name="test-func" select=" ‘less-than-eq’ "/> <xsl:with-param name="test-param1" select="10"/> </xsl:call-template> </xsl:template>

<xsl:template match="node( )" mode="generic:gen-set"> <xsl:value-of select="."/>

<xsl:text> </xsl:text> </xsl:template>

1 4 9 16 25 36 49 64 81 100

Вторая обобщенная функция, которую мы рассмотрим, генерирует набор уз­лов, n раз вызывая некоторую функцию, причем при первом вызове ей передается заданное начальное значение, а при каждом последующем – результат предыду­щего вызова:

<xsl:template name="generic:gen-nested"> <xsl:param name="x" select="1"/> <xsl:param name="func" select=" ‘identity’ "/> <xsl:param name="func-param1"

select="$generic:generics[self::generic:func and @name = $func]/@param1"/> <xsl:param name="i" select="1"/> <xsl:param name="n" select="2"/> <xsl:param name="result">

<xsl:value-of select="$x"/> </xsl:param>

<xsl:choose>

<xsl:when test="$i &lt;= $n"> <!– Вычислить func($x) –> <xsl:variable name="f-of-x"> <xsl:apply-templates

select="$generic:generics[self::generic:func and

@name = $func]"> <xsl:with-param name="x" select="$x"/> <xsl:with-param name="i" select="$i"/> <xsl:with-param name="param1" select="$func-param1"/> </xsl:apply-templates> </xsl:variable>

<xsl:call-template name="generic:gen-nested"> <xsl:with-param name="x" select="$f-of-x"/> <xsl:with-param name="func" select="$func"/> <xsl:with-param name="func-param1" select="$func-param1"/> <xsl:with-param name="i" select="$i + 1"/> <xsl:with-param name="n" select="$n"/> <xsl:with-param name="result"

select="exslt:node-set($result) | exslt:node-set($f-of-x)"/> </xsl:call-template>

</xsl:when> <xsl:otherwise>

<xsl:apply-templates select="$result" mode="generic:gen-nested"/> </xsl:otherwise> </xsl:choose> </xsl:template>

<xsl:template match="node( )" mode="generic:gen-nested"> <gen-nested>

<xsl:copy-of select="."/> </gen-nested> </xsl:template>

Ниже этот шаблон используется для построения последовательности 2, 2 ** 2, (2 ** 2) ** 2, ((2 ** 2) ** 2) ** 2, (((2 ** 2) ** 2) ** 2) ** 2, где ** означает возведение в степень:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:generic="http://www.ora.com/XSLTCookbook/namespaces/generic">

<xsl:import href="aggregation.xslt"/>

<xsl:output method="text" />

<xsl:template match="/">

<xsl:call-template name="generic:gen-nested"> <xsl:with-param name="x" select="2"/> <xsl:with-param name="func" select=" ‘square’ "/> <xsl:with-param name="n" select="4"/> </xsl:call-template> </xsl:template>

<xsl:template match="node( )" mode="generic:gen-nested"> <xsl:value-of select="."/> <xsl:text> </xsl:text> </xsl:template>

</xsl:stylesheet> 2 4 16 256 65536

Обсуждение

В рецептах 16.2 и 16.3 приведены преобразования вида многие-к-одному, а в рецепте 16.5 речь шла о преобразованиях вида многие-к-многим. Естественно, эту главу нельзя было бы считать полной без рассмотрения обобщенного преобра­зования один-к-одному.

С помощью генератора можно порождать случайные числа для отбора случай­ных узлов из XML-документа. В этой главе описывается простой линейно-конгруэн­тный генератор (см., например, http://www.taygeta.com/rwalks/node1.html). Следу­ющая таблица стилей выводит случайную выборку имен из входного документа:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:generic="http://www.ora.com/XSLTCookbook/namespaces/generic">

<xsl:import href="aggregation.xslt"/>

<xsl:output method="xml" indent="yes"/>

<!– Расширить набор имеющихся обобщенных функций –>

<xsl:variable name="generic:generics" select="$generic:public-generics | document(”)/*/generic:*"/>

<!– При таких начальных значениях получаются достаточно случайные –> <!– результаты, но можете поэкспериментировать с другими –> <xsl:variable name="a" select="168 0 7"/> <xsl:variable name="c" select="0"/> <xsl:variable name="m" select="214 7 4 8 3 64 7"/>

<!– Сохранить корневой элемент для последующего использования –> <xsl:variable name="doc" select="/"/>

<!– Генератор случайных чисел –> <generic:func name="linear-congruential"/>

<xsl:template match="generic:func[@name=’linear-congruential’]"> <xsl:param name="x"/>

<xsl:value-of select="($a * $x + $c) mod $m"/> </xsl:template>

<xsl:template match="/"> <names>

<xsl:call-template name="generic:gen-nested"> <xsl:with-param name="x" select="1"/>

<xsl:with-param name="func" select=" ‘linear-congruential’ "/> <xsl:with-param name="n" select="100"/> <!– Не включаем начальное значение –> <xsl:with-param name="result" select="/.."/> </xsl:call-template> </names> </xsl:template>

<xsl:template match="node( )" mode="generic:gen-nested">

<!– Ограничиваемся диапазоном от 1 до 100 –> <xsl:variable name="random" select=". mod 99 + 1"/>

<name>

<xsl:value-of select="$doc/names/name[$random]"/> </name>

</xsl:template>

</xsl:stylesheet>

 

 

Мангано Сэл  XSLT. Сборник рецептов. – М.: ДМК Пресс, СПБ.: БХВ-Петербург, 2008. – 864 с.: ил.

По теме:

  • Комментарии