This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kItemBy1stLetter" match="item"
use="substring(.,1,1)"/>
<xsl:variable name="vDoc" select="/"/>
<xsl:variable name="vAlphabet" select=
"'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"
/>
<my:message>No items found.</my:message>
<xsl:variable name="vMessage" select="document('')/*/my:message"/>
<xsl:template match="/">
<xsl:for-each select=
"(document('')//node()|document('')//@*|document('')//namespace::*)
[ not(position() > 26)]
">
<xsl:variable name="vcurLetter" select=
"substring($vAlphabet, position(), 1)"/>
<xsl:for-each select="$vDoc">
<xsl:variable name="vSearchResult" select=
"key('kItemBy1stLetter', $vcurLetter)"/>
<xsl:value-of select="concat('
',$vcurLetter, ': 
')"/>
<xsl:copy-of select="$vSearchResult | $vMessage[not($vSearchResult)]/text()"/>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document (playing the role of "database"):
<database>
<item>Bicycles</item>
<item>Computers</item>
<item>Cars</item>
<item>Forks</item>
<item>Gellato</item>
<item>Hypervehicles</item>
<item>Ichtiosaurs</item>
<item>Jobs</item>
<item>Knots</item>
<item>Lens</item>
<item>Miracles</item>
<item>Notes</item>
</database>
produces the wanted result:
A:
No items found.
B:
<item>Bicycles</item>
C:
<item>Computers</item>
<item>Cars</item>
D:
No items found.
E:
No items found.
F:
<item>Forks</item>
G:
<item>Gellato</item>
H:
<item>Hypervehicles</item>
I:
<item>Ichtiosaurs</item>
J:
<item>Jobs</item>
K:
<item>Knots</item>
L:
<item>Lens</item>
M:
<item>Miracles</item>
N:
<item>Notes</item>
O:
No items found.
P:
No items found.
Q:
No items found.
R:
No items found.
S:
No items found.
T:
No items found.
U:
No items found.
V:
No items found.
W:
No items found.
X:
No items found.
Y:
No items found.
Z:
No items found.