Задача
Допустим, у нас на сайте есть у нас нечто иерархическое. Например, категории товаров. У категорий есть подкатегории и так далее. И эта структура выражается в следующей 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>
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>
В результате мы получим вот такую картину
В общем-то, работает, но хочется, чтобы дерево категорий и выглядело, как дерево. А, так как у нас тут select
, то получить это дерево можно только, расставив по нужным местам пробелы. Есть, конечно, optgroup
-ы, но они в данном случае нас не спасут, потому что у категорий может быть сколь угодно большая вложенность.
Решение
Вот такой велосипед решает заданную задачу:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes"/> <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: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:stylesheet>
В итоге получаем следующее:
2 комментария:
Есть же в стандартном html аналог group select
Если Вы про optgroup, то там две особенности. Во-первых, нельзя делать произвольную вложенность. Категорию с подкатегориями сделать можно, а вот подкатегории подкатегорий уже нельзя. А во-вторых нельзя выбирать сами optgroup-ы. В некоторых случаях это имеет смысл, но у меня была другая задача.
Отправить комментарий