In XSLT 2.0 wäre das mit den neuen Gruppierungsfunktionen recht einfach.
In XSLT 1.0 ist es ein wenig komplizierter, aber es funktioniert:
<xsl:template match="/tree">
<xhtml>
<head/>
<body>
<ul>
<xsl:apply-templates select="node[depth='0']"/>
</ul>
</body>
</xhtml>
</xsl:template>
<xsl:template match="node">
<xsl:variable name="thisNodeId" select="generate-id(.)"/>
<xsl:variable name="depth" select="depth"/>
<xsl:variable name="descendants">
<xsl:apply-templates select="following-sibling::node[depth = $depth + 1][preceding-sibling::node[depth = $depth][1]/generate-id() = $thisNodeId]"/>
</xsl:variable>
<li>
<xsl:value-of select="name"/>
</li>
<xsl:if test="$descendants/*">
<ul>
<xsl:copy-of select="$descendants"/>
</ul>
</xsl:if>
</xsl:template>
Der Kern der Sache ist die lange und hässliche "descendants"-Variable, die nach Knoten nach dem aktuellen Knoten, die eine "Tiefe" Kind größer als die aktuelle Tiefe haben, aber nicht nach einem anderen Knoten, die die gleiche Tiefe wie die aktuelle Tiefe haben würde (weil, wenn sie waren, würden sie Kinder dieses Knotens statt der aktuellen ein sein) sucht.
Übrigens gibt es einen Fehler in Ihrem Beispielergebnis: "FLASH" sollte ein Kind von "MP3 PLAYERS" sein und nicht ein Geschwisterkind.
EDITAR
In der Tat (wie in den Kommentaren erwähnt) funktioniert dies in "reinem" XSLT 1.0 aus zwei Gründen nicht: Der Pfadausdruck verwendet generate-id() falsch, und man kann kein "Ergebnisbaumfragment" in einem Pfadausdruck verwenden.
Hier ist eine korrekte XSLT 1.0 Version des "node" Templates (erfolgreich getestet mit Saxon 6.5), die weder EXSLT noch XSLT 1.1 verwendet:
<xsl:template match="node">
<xsl:variable name="thisNodeId" select="generate-id(.)"/>
<xsl:variable name="depth" select="depth"/>
<xsl:variable name="descendants">
<xsl:apply-templates select="following-sibling::node[depth = $depth + 1][generate-id(preceding-sibling::node[depth = $depth][1]) = $thisNodeId]"/>
</xsl:variable>
<xsl:variable name="descendantsNb">
<xsl:value-of select="count(following-sibling::node[depth = $depth + 1][generate-id(preceding-sibling::node[depth = $depth][1]) = $thisNodeId])"/>
</xsl:variable>
<li>
<xsl:value-of select="name"/>
</li>
<xsl:if test="$descendantsNb > 0">
<ul>
<xsl:copy-of select="$descendants"/>
</ul>
</xsl:if>
</xsl:template>
Natürlich sollte man den Pfadausdruck, der wiederholt wird, faktorisieren, aber ohne die Möglichkeit, "Ergebnisbaumfragmente" in XML zu verwandeln, das tatsächlich verarbeitet werden kann, weiß ich nicht, ob das möglich ist? (das Schreiben einer benutzerdefinierten Funktion würde den Trick natürlich erledigen, aber dann ist es viel einfacher, EXSLT zu verwenden)
Fazit: Verwenden Sie XSLT 1.1 oder EXSLT, wenn Sie können!
2. Bearbeitung
Um zu vermeiden, dass der Pfadausdruck wiederholt werden muss, können Sie den Test auch ganz weglassen. Das Ergebnis ist dann einfach eine leere Stelle, die Sie entweder im Ergebnis belassen oder durch Nachbearbeitung eliminieren können.