Это то, что я бы сделал в качестве первого прохода:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/Tree">
<cells>
<xsl:apply-templates select="Item[1]" mode="sibling">
<xsl:with-param name="row" select="1"/>
<xsl:with-param name="col" select="1"/>
</xsl:apply-templates>
</cells>
</xsl:template>
<xsl:template match="Item" mode="sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<cell row="{$row}" col="{$col}">
<xsl:value-of select="Label"/>
</cell>
<xsl:apply-templates select="following-sibling::*[1]" mode="sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="ColumnBreak" mode="sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col + 1"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="RowBreak" mode="sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="sibling">
<xsl:with-param name="row" select="$row + 1"/>
<xsl:with-param name="col" select="1"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
Применительно к вашему примеру ввода это приведет к:
Результат
<?xml version="1.0" encoding="UTF-8"?>
<cells>
<cell row="1" col="1">Item 1</cell>
<cell row="1" col="1">Item 2</cell>
<cell row="1" col="2">Item 3</cell>
<cell row="1" col="2">Item 4</cell>
<cell row="1" col="2">Item 5</cell>
<cell row="2" col="1">Item 6</cell>
<cell row="2" col="1">Item 7</cell>
<cell row="2" col="2">Item 8</cell>
<cell row="3" col="1">Item 9</cell>
<cell row="3" col="1">Item 10</cell>
</cells>
, с которым действительно можно работать.
Добавлено:
Вот полная таблица стилейкоторый обрабатывает ввод за два прохода:
- при первом проходе используется рекурсия брата , как описано выше;
- второй проход выполняет мюнхенскую группировку по строкам и столбцам для создания таблицы, описанной в исходном документе:
XSLT 1.0 (с расширением EXSLT node-set()
функция)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="cell-by-row" match="cell" use="@row" />
<xsl:key name="cell-by-col" match="cell" use="concat(@row, '|', @col)" />
<xsl:template match="/Tree">
<!-- first-pass -->
<xsl:variable name="cells">
<xsl:apply-templates select="Item[1]" mode="sibling">
<xsl:with-param name="row" select="1"/>
<xsl:with-param name="col" select="1"/>
</xsl:apply-templates>
</xsl:variable>
<!-- output -->
<table border = "1">
<!-- for each distinct row -->
<xsl:for-each select="exsl:node-set($cells)/cell[count(. | key('cell-by-row', @row)[1]) = 1]">
<tr>
<!-- for each distinct cell in the current row -->
<xsl:for-each select="key('cell-by-row', @row)[count(. | key('cell-by-col', concat(@row, '|', @col))[1]) = 1]">
<td>
<!-- get the values in the current cell -->
<xsl:for-each select="key('cell-by-col', concat(@row, '|', @col))">
<xsl:value-of select="."/>
<br/>
</xsl:for-each>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="Item" mode="sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<cell row="{$row}" col="{$col}">
<xsl:value-of select="Label"/>
</cell>
<xsl:apply-templates select="following-sibling::*[1]" mode="sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="ColumnBreak" mode="sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="sibling">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="col" select="$col + 1"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="RowBreak" mode="sibling">
<xsl:param name="row"/>
<xsl:param name="col"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="sibling">
<xsl:with-param name="row" select="$row + 1"/>
<xsl:with-param name="col" select="1"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
Результат
<?xml version="1.0" encoding="utf-8"?>
<table border="1">
<tr>
<td>Item 1<br/>Item 2<br/></td>
<td>Item 3<br/>Item 4<br/>Item 5<br/></td>
</tr>
<tr>
<td>Item 6<br/>Item 7<br/></td>
<td>Item 8<br/></td>
</tr>
<tr>
<td>Item 9<br/>Item 10<br/></td>
</tr>
</table>
Оказано