Способ думать о проблемах любой сложности в XSLT не в том, «как бы я написал программу для получения Y, учитывая X в качестве входных данных?» а точнее, «учитывая выходные данные Y, какой X я собираюсь преобразовать, чтобы произвести его?» Это не простой принцип, чтобы понять (или сформулировать), но как только вы его получите, то, что кажется трудным в XSLT, становится тривиальным.
Если вывод представляет собой серию tr
элементов, например:
<tr>
<td>a</td><td>b</td><td>c</td>
</tr>
<tr>
<td>d</td><td>e</td><td>f</td>
</tr>
<tr>
<td>g</td><td>h</td><td>i</td>
</tr>
<tr>
<td>j</td><td/><td/>
</tr>
Есть, по сути, четыре выходных элемента. Таким образом, должно быть четыре элемента ввода.
Первый вопрос: какие четыре? Совершенно ясно, что это будет 1-й, 4-й, 7-й и 10-й, то есть каждые 3 элемента, начиная с первого. Итак, вашей отправной точкой является преобразование этих четырех элементов:
<xsl:apply-templates select="/order/item[position() mod 3 = 1]"/>
Хорошо, а теперь, когда мы выбрали каждый третий элемент, как мы собираемся создать tr
из него и элементов сразу после него? Использование оси following-sibling
:
<xsl:template match="item">
<tr>
<td><xsl:value-of select="@name"/></td>
<td><xsl:value-of select="following-sibling::item[1]/@name"/></td>
<td><xsl:value-of select="following-sibling::item[2]/@name"/></td>
</tr>
</xsl:template>
Это хорошо, насколько это возможно. Но есть довольно много дублирующегося кода, и вы должны его изменить, если хотите (скажем) изменить количество столбцов с 3 на 6. Вы можете удалить дублирующийся код, сделав другой шаблон:
<xsl:template match="item">
<tr>
<xsl:apply-templates select="@name | following-sibling::item[position() <= 3]/@name"/>
</tr>
</xsl:template>
<xsl:template match="@name">
<td><xsl:value-of select="."/></td>
</xsl:template>
И вы можете параметризовать количество столбцов, поместив его в переменную, как это сделал Димитр в своем примере.