たとえば、次のような要素の XML ドキュメントがあるとします。
<items>
<item>Access</item>
<item>Autocad</item>
<item>Burger</item>
<item>Layout</item>
<item>Photoshop</item>
<item>Sandwich</item>
<item>VisualStudio</item>
</items>
そして、それらを 3 つの列にグループ化したいのですが、アイテムは左から右ではなく、最初に上から下に実行されます。現在のテスト$Position mod 3 = 0
は部分的に正しい行に沿っていますが、実際にはここで新しい行を開始しているため、左から右に進みます。
言及すべきことの1つは、このコード行の使用です
<xsl:text disable-output-escaping="yes"></tr></xsl:text>
単純に要素を繰り返し処理しているように見え、3 つごとに終了タグを出力しようとしています。XSLT は関数型言語であるため、通常の手続き型言語とは異なる考え方でアプローチし、異なる方法で物事を行う必要があります。
まず、出力する行数を見つける必要があります
<xsl:param name="columns" select="3"/>
<xsl:variable name="items" select="count(/*/item)"/>
<xsl:variable name="rows" select="ceiling($items div $columns)"/>
つまり、行は項目の総数を列の数で割ったものです。
次に、各行の最初の項目を選択する必要があります。これらはリストの最初の「n」項目になるため、簡単です (最終的な XSLT には項目要素に一致する 2 つのテンプレートがあるため、モードの使用に注意してください)
<xsl:apply-templates select="item[position() <= $rows]" mode="row"/>
開始アイテムに一致するテンプレート内で、現在のアイテムと、行にある次の兄弟アイテムを出力する必要があります
<xsl:apply-templates select=".|following-sibling::item[position() mod $rows = 0]"/>
他に考慮すべき唯一のことは、いくつかの行の最後に空白のセルを追加することです。これは、合計アイテムと比較して残りのアイテムの数を計算することによって行うことができます
<xsl:variable name="lastItem" select="(position() + $rows * ($columns - 1) - $items)" />
<xsl:if test="$lastItem > 0">
<td colspan="{ceiling($lastItem div $rows)}"></td>
</xsl:if>
次の XSLT を試してください
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="columns" select="3"/>
<xsl:variable name="items" select="count(/*/item)"/>
<xsl:variable name="rows" select="ceiling($items div $columns)"/>
<xsl:template match="/*">
<table>
<xsl:apply-templates select="item[position() <= $rows]" mode="row"/>
</table>
</xsl:template>
<xsl:template match="item" mode="row">
<tr>
<xsl:apply-templates select=".|following-sibling::item[position() mod $rows = 0]"/>
<xsl:variable name="lastItem" select="(position() + $rows * ($columns - 1) - $items)" />
<xsl:if test="$lastItem > 0">
<td colspan="{ceiling($lastItem div $rows)}"></td>
</xsl:if>
</tr>
</xsl:template>
<xsl:template match="item">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
</xsl:stylesheet>
質問の冒頭に示した XML に適用すると、次のように出力されます。
<table>
<tr>
<td>Access</td>
<td>Layout</td>
<td>VisualStudio</td>
</tr>
<tr>
<td>Autocad</td>
<td>Photoshop</td>
<td colspan="1"></td>
</tr>
<tr>
<td>Burger</td>
<td>Sandwich</td>
<td colspan="1"></td>
</tr>
</table>