В основном вам нужно сгруппировать по первой букве и отсортировать по <name>
. Вы уже хорошо справляетесь с подходом мюнхенской группировки.
Я бы предложил альтернативу, которая немного проще для глаз:
<xsl:key name="kInitial" match="course" use="substring(name, 1, 1)" />
<xsl:template match="courses">
<xsl:apply-templates select="course" mode="initial">
<xsl:sort select="name" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="course" mode="initial">
<xsl:variable name="initial" select="substring(name, 1, 1)" />
<xsl:variable name="courses" select="key('kInitial', $initial)" />
<xsl:if test="generate-id() = generate-id($courses[1])">
<h2><xsl:value-of select="$initial"/></h2>
<ul>
<xsl:apply-templates select="$courses">
<xsl:sort select="name" />
</xsl:apply-templates>
</ul>
</xsl:if>
</xsl:template>
<xsl:template match="course">
<li>
<xsl:value-of select="name"/>
</li>
</xsl:template>
выходы:
<h2>6</h2>
<ul>
<li>6500 Training</li>
<li>6600 Training</li>
</ul>
<h2>A</h2>
<ul>
<li>Accelerated Training</li>
</ul>
<h2>T</h2>
<ul>
<li>Training</li>
</ul>
РЕДАКТИРОВАТЬ: Ради разборчивости я пропустил верхний регистр первой буквы. Правильный ключ будет таким (вы не можете использовать переменную в ключе, следовательно, строки буквального алфавита):
<xsl:key name="kInitial" match="course" use="
translate(
substring(name, 1, 1),
'abcdefghijklmnopqrstuvwxyz',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
)
" />
То же самое относится и к переменной $initial
во втором шаблоне, но здесь вы можете использовать переменные снова.
РЕДАКТИРОВАТЬ # 2: Поскольку сортировка также чувствительна к регистру, вы можете использовать то же выражение:
<xsl:sort select="translate(substring(name, 1, 1), $vLower, $vUpper)" />