Допустим, у нас на сайте есть у нас нечто иерархическое. Например, категории товаров. У категорий есть подкатегории и так далее. И пусть нам захотелось вывести эту иерархию в выпадающий список.
К примеру, наша структура выражается в следующей XML-ке:
Итак, нам стало нужно сформировать из этой XML-ки выпадающий список. Простейший способ это сделать — написать следующее преобразование:
В результате мы получим вот такую картину
![Некрасивый список](https://habrastorage.org/r/w1560/getpro/habr/post_images/d6b/9d0/749/d6b9d07494439d83de27a9c124fe3c1f.png)
В общем-то, работает, но хочется, чтобы дерево категорий и выглядело, как дерево. А, так как у нас тут
Вот такой велосипед решает заданную задачу:
К примеру, наша структура выражается в следующей XML-ке:
<categories>
<category id="1" title="Процессоры">
<categories>
<category id="2" title="Intel">
<categories>
<category id="3" title="Intel Core LGA775">
<categories/>
</category>
<category id="4" title="Intel Core i7 LGA1366">
<categories/>
</category>
</categories>
</category>
<category id="6" title="AMD">
<categories>
<category id="6" title="AMD Athlon AM2">
<categories/>
</category>
<category id="7" title="AMD Athlon II AM3">
<categories/>
</category>
</categories>
</category>
</categories>
</category>
<category id="8" title="Жесткие диски">
<categories>
<category id="9" title="SATA">
<categories>
<category id="10" title="Seagate">
<categories />
</category>
<category id="11" title="Western Digital">
<categories />
</category>
</categories>
</category>
<category id="12" title="IDE">
<categories>
<category id="13" title="Seagate">
<categories />
</category>
<category id="14" title="Western Digital">
<categories />
</category>
</categories>
</category>
</categories>
</category>
</categories>
* This source code was highlighted with Source Code Highlighter.
NB: На самом деле хранить строки в атрибутах не есть хорошо, их стоит делать отдельными узлами и заворачивать в CDATA. Однако, здесь title является именно атрибутом в целях экономии места. Так что прошу не брать дурной пример.Итак, нам стало нужно сформировать из этой XML-ки выпадающий список. Простейший способ это сделать — написать следующее преобразование:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="categories">
<select>
<option value="0">Корневая категория</option>
<xsl:apply-templates select="//category"/>
</select>
</xsl:template>
<xsl:template match="category">
<option value="{@id}">
<xsl:value-of select="@title"/>
</option>
</xsl:template>
</xsl:stylesheet>
* This source code was highlighted with Source Code Highlighter.
В результате мы получим вот такую картину
![Некрасивый список](https://habrastorage.org/getpro/habr/post_images/d6b/9d0/749/d6b9d07494439d83de27a9c124fe3c1f.png)
В общем-то, работает, но хочется, чтобы дерево категорий и выглядело, как дерево. А, так как у нас тут
select
, то получить это дерево можно только, расставив по нужным местам пробелы. Есть, конечно, optgroup
-ы, но они в данном случае нас не спасут, потому что у категорий может быть сколь угодно большая вложенность.Решение
Вот такой велосипед решает заданную задачу:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<select>
<option value="0">Корневая категория</option>
<xsl:call-template name="cat_tree">
<xsl:with-param name="space" select="'  '"/>
</xsl:call-template>
</select>
</xsl:template>
<xsl:template name="cat_tree" match="categories">
<xsl:param name="space" />
<xsl:for-each select="categories/category">
<option value="{@id}">
<xsl:value-of select="$space" />
<xsl:value-of select="@title"/>
</option>
<xsl:if test="./categories" >
<xsl:call-template name="cat_tree">
<xsl:with-param name="space" select="concat($space, '  '
)"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
* This source code was highlighted with Source Code Highlighter.
В итоге получаем следующее:
![Красивое дерево](https://habrastorage.org/r/w1560/getpro/habr/post_images/9e8/7f4/5b9/9e87f45b9a7315e9859381c2c9e217e4.png)