</category>
</catalog>
При отображении этого дерева мы будем раскрывать только определенную выбранную ветвь категорий. Скажем, если пользователь выбрал категорию 'Расходные материалы', показывать информацию о компьютерах мы ему не будем. Иными словами, мы будем показывать только те категории, которые являются надкатегориями выбранной. Для того чтобы сделать это как можно эффективнее, мы выполним следующие шаги.
□ При помощи ключа и уникального идентификатора, сгенерированного функцией generate-id
, мы найдем в дереве требуемую категорию и присвоим ее переменной $category
.
□ Воспользовавшись осью ansector-or-self
, мы найдем все надкатегории данной, то есть все категории, которые прямо или косвенно содержат найденную. Путь выборки будет иметь вид $category/ancestor-or-self::category
. Найденное множество мы присвоим переменной $path
.
□ При обработке каждой из категорий мы будем обрабатывать ее подкатегории только в том случае, если она является надкатегорией выбранной; иначе говоря — только в том случае, когда ее узел принадлежит множеству узлов $path
. Проверять это мы будем при помощи условия count(.|$path)=count($path)
.
Искомое преобразование в итоге запишется в виде.
<?xml version='1.0' encoding='windows-1251'?>
<xsl:stylesheet
version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<!-- Выводим документ в формате html и кодировке windows-1251 -->
<xsl:output method='html' encoding='windows-1251'/>
<!--
| Переменная, которая содержит уникальный
| идентификатор выбранного узла дерева
+-->
<xsl:param name='current' select=''''/>
<!-- Определение ключа категории -->
<xsl:key name='cat' match='category' use='generate-id(.)'/>
<!-- Находим текущую категорию -->
<xsl:variable name='category' select='key('cat',$current)'/>
<!--
| Находим надкатегории текущей категории, узлы которых
| мы будем раскрывать в дереве
+-->
<xsl:variable name='path'
select='$category/ancestor-or-self::category'/>
<!-- Шаблон обработки каталога -->
<xsl:template match='catalog'>
<xsl:apply-templates select='category'/>
</xsl:template>
<!-- Шаблон обработки категории-->
<xsl:template match='category'>
<!-- Параметр, указывающий отступ -->
<xsl:param name='indent'/>
<!-- Выводим отступ -->
<xsl:value-of select='$indent'/>
<!-- Выводим информацию о категории в виде ссылки -->
<а href='javascript:expand('{generate-id(.)}')'>
<!-- Перед названием категории выводим соответствующую иконку -->
<img height='11' width='11' border='0'>
<xsl:choose>
<!--
| Если категория не содержит субэлементов,
| выводим иконку с точкой
+-->
<xsl:when test='not(*)'>
<xsl:attribute name='src'>images/dot.gif</xsl:attribute>
</xsl:when>
<!--
| Если категория принадлежит ветке выбранной категории,
| выводим иконку с минусом, что означает раскрытую ветку
+-->
<xsl:when test='count(.|$path)=count($path)'>
<xsl:attribute name='src'>images/minus.gif</xsl:attribute>
</xsl:when>
<!--
| Если категория не принадлежит ветке выбранной категории,
| выводим иконку с плюсом, что означает нераскрытую ветку
+-->
<xsl:otherwise>
<xsl:attribute name='src'>images/plus.gif</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</img>
<!--
| Выводим неразрывный пробел.
|   в Unicode соответствует
+-->
<xsl:text> </xsl:text>
<!-- Выводим название категории -->
<xsl:value-of select='@title'/>
</a>
<br/><xsl:text>
</xsl:text>
<!--
| Если категория принадлежит раскрываемой ветке,
| обрабатываем ее подкатегории
+-->
<xsl:if test='count(.|$path)=count($path)'>
<xsl:apply-templates select='category'>
<!-- Увеличиваем отступ на три пробела -->
<xsl:with-param name='indent'
select='concat($indent,'   ')'/>