Вариант моего ответа на ваша часть 1 вопроса делает это :
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<!-- prepare some keys for later use -->
<xsl:key name="kWidgetsByShape" match="widget" use="@shape" />
<xsl:key name="kWidgetsByMaterial" match="widget" use="@material" />
<xsl:key name="kWidgetsByComposition" match="widget" use="concat(@shape, ',', @material)" />
<!-- select the <widget>s that are the first in their respective @shape -->
<xsl:variable name="vShapes" select="
/widgets/widget[
generate-id()
=
generate-id(key('kWidgetsByShape', @shape)[1])
]
" />
<!-- select the <widget>s that are the first in their respective @material -->
<xsl:variable name="vMaterials" select="
/widgets/widget[
generate-id()
=
generate-id(key('kWidgetsByMaterial', @material)[1])
]
" />
<!-- output basic table structure -->
<xsl:template match="/widgets">
<table title="shapes: {count($vShapes)}, materials: {count($vMaterials)}">
<xsl:apply-templates select="$vShapes" mode="tr">
<xsl:sort select="@shape" />
</xsl:apply-templates>
</table>
</xsl:template>
<!-- output the <tr>s, one for each @shape -->
<xsl:template match="widget" mode="tr">
<tr id="{@shape}">
<xsl:apply-templates select="$vMaterials" mode="td">
<xsl:sort select="@material" />
<xsl:with-param name="vCurrentShape" select="@shape" />
</xsl:apply-templates>
</tr>
</xsl:template>
<!-- output the right number of <td>s in each row, empty or not -->
<xsl:template match="widget" mode="td">
<xsl:param name="vCurrentShape" />
<xsl:variable
name="vWidget"
select="key('kWidgetsByComposition', concat($vCurrentShape, ',', @material))[1]"
/>
<td class="{normalize-space(concat(@material, ' ', $vWidget/@color))}">
<xsl:apply-templates select="$vWidget" />
</td>
</xsl:template>
<xsl:template match="widget">
<xsl:value-of select="." />
</xsl:template>
</xsl:stylesheet>
Который производит:
<table title="shapes: 3, materials: 4">
<tr id="diamond">
<td class="kevlar"></td>
<td class="metal red"></td>
<td class="plastic blue"></td>
<td class="wood brown"></td>
</tr>
<tr id="round">
<td class="kevlar blue"></td>
<td class="metal orange"></td>
<td class="plastic"></td>
<td class="wood green"></td>
</tr>
<tr id="square">
<td class="kevlar red"></td>
<td class="metal blue"></td>
<td class="plastic green"></td>
<td class="wood red"></td>
</tr>
</table>
В основном все, что я сказал в моем другом ответе, все еще применимо.
На этот раз я использовал три <xsl:key>
с вместо двух. Два из них используются для итерации, а один - для поиска <widget>
s по @shape
и @material
.
Я использую различные режимы шаблонов вместе с <xsl:apply-templates>
вместо <xsl:for-each>
. Это делает код на несколько строк длиннее, но это выгодно для ясности и читабельности.
Последний шаблон (<xsl:template match="widget">
) предназначен только для демонстрации и показывает, как вы можете продолжать. Он вызывается изнутри <xsl:template match="widget" mode="td">
, один раз для каждого <widget>
, который действительно существует.