Pull to refresh

Многоуровневое меню в XSLT

Reading time 3 min
Views 3.9K
Здравствуйте уважаемые Хабровчане. Хочу представить шаблон вывода многоуровневого меню, хотя, немного переделав, сойдет для вывода обычных деревьев. На нашем любимом сайте подобного не видел, в инете особо не искал. Для кого-то может показаться слишком легким, но надеюсь другим понадобиться.

Вот здесь уже разбиралась тема построение деревьев. В этом примере другая структура XML файла и заточка под другие задачи.

Начнем с XML файла. Структура не сложная. Каждый элемент состоит из идентификатора, идентификатора родительского элемента, ссылки и названия.


menu.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="menu.xsl"?> 
<root>
	<item id="1" idParent="0" link="#" title="Ссылка 1"/>
	<item id="2" idParent="1" link="#" title="Ссылка 2"/>
	<item id="3" idParent="1" link="#" title="Ссылка 3"/>
	<item id="4" idParent="2" link="#" title="Ссылка 4"/>
	<item id="5" idParent="2" link="#" title="Ссылка 5"/>
	<item id="6" idParent="1" link="#" title="Ссылка 6"/>
	<item id="7" idParent="6" link="#" title="Ссылка 7"/>
	<item id="8" idParent="6" link="#" title="Ссылка 8"/>
	<item id="9" idParent="0" link="#" title="Ссылка 9"/>
</root>

Не долго думая выведем шаблон преобразования

menu.xsl
<?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" encoding="utf-8" omit-xml-declaration="yes" doctype-system="about:legacy-compat"/>
	
	<!-- Основное преобразование -->
	<xsl:template match="/">
		<html lang="ru">
			<head>
				<title>Многоуровневое меню</title>
			</head>
			<body>
				<h1>Многоуровневое меню</h1>
				<ul>
					<xsl:apply-templates select="/root/item[@idParent=0]"/>
				</ul>
			</body>
		</html>
	</xsl:template>

	<!-- Шаблон вывода меню -->
	<xsl:template match="/root/item">
		<xsl:variable name="id" select="@id"/>
		<!-- Вывод элемента меню -->
		<li>
			<a href="{@link}">
				<xsl:value-of select="@title"/>
			</a>
			<!-- Если существют подпункты -->
			<xsl:if test="/root/item[@idParent=$id]">
				<ul>
					<xsl:apply-templates select="/root/item[@idParent=$id]"/>
				</ul>
			</xsl:if>
		</li>
	</xsl:template>

</xsl:stylesheet>

Шаблон преобразования состоит из двух частей. Первая выводит основные HTML теги и не особо интересна. Стоит только обратить внимание на вызов шаблона, который начинает вызов элементов с родительским идентификатором равным нулю.
Втора часть выводит пункт меню и проверяет, есть ли элементы с родительским идентификатором равным текущему идентификатору. Если есть, то рекурсивно вызывает этот же шаблон.

Естественно, пункты ссылающиеся на не существующих родителей отображаться не будут.

Сохраняем menu.xml и menu.xsl в одной папке и в браузере запускаем первый. Видим вот такую картину.

Вывод меню
image

P. S. Спасибо Dart за найденные ошибки.
Tags:
Hubs:
+1
Comments 5
Comments Comments 5

Articles