Here is a more efficient solution, using the classical Muenchian method for grouping -- with keys.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vLower" select=
"'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="vUpper" select=
"'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:key name="kTitleBy1stLetter" match="database"
use="substring(title_display,1,1)"/>
<xsl:template match="/*">
<xsl:for-each select=
"database
[generate-id()
=
generate-id(key('kTitleBy1stLetter',
substring(title_display,1,1)
)[1]
)
]"
>
<xsl:variable name="v1st"
select="substring(title_display,1,1)"/>
<h2><xsl:value-of select="$v1st"/></h2>
<div class="{translate($v1st,
$vUpper,
$vLower)}-content">
<ul>
<xsl:for-each select=
"key('kTitleBy1stLetter',$v1st)">
<li><xsl:value-of select="title_display"/></li>
</xsl:for-each>
</ul>
</div>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When applied on the originally provided XML document:
<databases>
<database>
<title_display>Aardvark</title_display>
</database>
<database>
<title_display>Apple</title_display>
</database>
<database>
<title_display>Blue</title_display>
</database>
<database>
<title_display>Car</title_display>
</database>
</databases>
produces exactly the wanted result:
<h2>A</h2>
<div class="a-content">
<ul>
<li>Aardvark</li>
<li>Apple</li>
</ul>
</div>
<h2>B</h2>
<div class="b-content">
<ul>
<li>Blue</li>
</ul>
</div>
<h2>C</h2>
<div class="c-content">
<ul>
<li>Car</li>
</ul>
</div>
Do note, that the Muenchian method is hugely more efficient than the O(N^2) solution that uses comparison of all database
elements on the preceding-sibling::
axis.
Also, this solution produces the class
attributes value with the required capitalization.