Во-первых, вам не нужно группировать.Эта таблица стилей:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="books/*">
<p>
<xsl:value-of
select="concat(translate(
substring(local-name(),1,1),
'qwertyuiopasdfghjklzxcvbnm',
'QWERTYUIOPASDFGHJKLZXCVBNM'
),
substring(local-name(),2),
': ',
.
)" />
</p>
</xsl:template>
</xsl:stylesheet>
Вывод:
<p>Title: book_one</p>
<p>Price: price_for_book_one</p>
<p>Notes: notes_for_book_one</p>
<p>Title: book_two</p>
<p>Price: price_for_book_two</p>
Группировка потребуется, только если вы собираетесь что-то сделать с группой, например, обтекание:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kElementByPrecedingTitle"
match="books/*"
use="generate-id((.|preceding-sibling::*)[self::title][last()])"/>
<xsl:template match="books/*">
<p>
<xsl:value-of
select="concat(translate(
substring(local-name(),1,1),
'qwertyuiopasdfghjklzxcvbnm',
'QWERTYUIOPASDFGHJKLZXCVBNM'
),
substring(local-name(),2),
': ',
.
)" />
</p>
</xsl:template>
<xsl:template match="books">
<xsl:for-each select="title">
<div class="book">
<xsl:apply-templates
select="key('kElementByPrecedingTitle',generate-id())"/>
</div>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Вывод:
<div class="book">
<p>Title: book_one</p>
<p>Price: price_for_book_one</p>
<p>Notes: notes_for_book_one</p>
</div>
<div class="book">
<p>Title: book_two</p>
<p>Price: price_for_book_two</p>
</div>