Сначала необходимо определить ключ для «группировки» всех элементов компании , которые имеют одну и ту же первую букву
<xsl:key name="companyLetter" match="company" use="substring(text(), 1, 1)" />
Далее вы должны выполнить итерацию по всей компании элементов
<xsl:for-each select="options/companies/company">
Однако вы хотите обработать элемент company только в том случае, если это первый элемент этого элемента для его первой буквы. Вы делаете это, ища первый элемент в вашем ключе для первой буквы, и проверяете, является ли это тем же самым. Сравнение элементов выполняется с помощью функции generate-id ()
<xsl:variable name="firstLetter" select="substring(text(), 1, 1)" />
<xsl:if test="generate-id(.) = generate-id(key('companyLetter', $firstLetter)[1])" >
Если положить это в целом, то получится
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:key name="companyLetter" match="company" use="substring(text(), 1, 1)"/>
<xsl:template match="/root">
<select id="colors">
<xsl:for-each select="options/companies/company">
<xsl:sort select="text()"/>
<xsl:variable name="firstLetter" select="substring(text(), 1, 1)"/>
<xsl:if test="generate-id(.) = generate-id(key('companyLetter', $firstLetter)[1])">
<option>
<xsl:attribute name="value">
<xsl:value-of select="$firstLetter"/>
</xsl:attribute>
<xsl:value-of select="$firstLetter"/>
</option>
</xsl:if>
</xsl:for-each>
</select>
</xsl:template>
</xsl:stylesheet>
Для второго раскрывающегося списка вы можете использовать именованный шаблон, которому передается буква в качестве параметра. Вы можете найти все элементы для этой буквы, используя ту же клавишу, что и выше.
<xsl:template name="Companies">
<xsl:param name="firstLetter"/>
<select>
<xsl:attribute name="id">
<xsl:value-of select="$firstLetter"/>
</xsl:attribute>
<xsl:for-each select="key('companyLetter', $firstLetter)">
<xsl:sort select="text()"/>
<option>
<xsl:attribute name="value">
<xsl:value-of select="@url"/>
</xsl:attribute>
<xsl:value-of select="text()"/>
</option>
</xsl:for-each>
</select>
</xsl:template>
Для вызова шаблона это просто случай передачи требуемого параметра, например
<xsl:call-template name="Companies">
<xsl:with-param name="firstLetter">B</xsl:with-param>
</xsl:call-template>
Конечно, вы можете поместить это цикл для каждого, если хотите показать все выпадающие списки для всех возможных первых букв.