В предыдущем выпуске (#6) я написал как разворачивать деревья, по существу XSLT-код ничем не отличается от того, как это делается на SQL или PHP или любом другом языке. А вот обратная задача - получение плоского списка сообщений из древовидного другими не-XSLT средствами решается как-то не очень изящно. И это понятно, потому что преобразование XML в XML делать какими-то другими, отличными от XSL средстваим не очень разумно.
Итак нам нужно свернуть ветку обсуждения блога, полученную в предыдущем выпуске (набор вложенных друг в друга ненумерованных списков) обратно - в XML набор в виде плоского списка, с указанием parent id. Фрагмент исходного дерева:
Свертывающее XSLT-преобразование выполним двумя способами.
Пример 1. Рекурсивное свертывание
<xsl:template match="/">
<item>
<xsl:apply-templates/>
</item>
</xsl:template>
<xsl:template match="li">
<xsl:param name="parentid" select="0"/>
<topic id="{@id}" parentid="{$parentid}" author="{h3}">
<xsl:value-of select="p"/>
</topic>
<!-- запуск на рекурсивную обработку вложенных сообщений -->
<xsl:apply-templates select="ul/li">
<xsl:with-param name="parentid" select="@id"/>
</xsl:apply-templates>
</xsl:template>
|
Сначала вызывается шаблон для формирования корневого элемента. Он формирует корневой элемент списка сообщений item и вызывает шаблоны по умолчанию. Первое сообщение будет отработано шаблоном match="li", которое формирует XML элемент этого сообщения и запускает на рекурсивную обработку все вложенные сообщения (ul/li)
На выходе получается примерно то, что было на входе в предыдущем примере, но порядок сообщений при этом нарушается. Чтобы порядок сообщений сохранялся необходимо ввести сортировку по id. Проделаем это в следующем примере.
Пример 2. Прямое свертывание
<xsl:template match="/">
<item>
<xsl:apply-templates select="//li">
<xsl:sort select="id" data-type="number"/>
</xsl:apply-templates>
</item>
</xsl:template>
<xsl:template match="li">
<xsl:variable name="parentid">
<xsl:choose>
<xsl:when test="ancestor::li[1]/@id"> <xsl:value-of select="ancestor::li[1]/@id"/> </xsl:when>
<xsl:otherwise> 0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<topic id="{@id}" author="{h3}" parentid="{$parentid}">
<xsl:value-of select="p"/>
</topic>
</xsl:template> |
Здесь в первом шаблоне (match="/"), обрабатыващем корневой элемент, задаем напрямую обработку всех сообщений (тегов li) с указанием порядка сортировки - по id. Второй шаблон (match="li") обрабатывающий отдельные сообщения, вычисляет id родительского элемента в переменной parentid и формирует соответствующий элемент сообщения <topic> в выходном дереве