Claro, no hay problema:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output indent="yes" />
<xsl:template match="/data">
<!-- copy the document element -->
<xsl:copy>
<!-- That's where we start: all "record" nodes that have no "\". -->
<xsl:apply-templates mode="recurse" select="/data/record[
not(contains(@Name, '\'))
]" />
</xsl:copy>
</xsl:template>
<xsl:template match="record" mode="recurse">
<xsl:param name="starting-path" select="''" />
<!-- The record node and its ID attribute can be copied. -->
<xsl:copy>
<xsl:copy-of select="@ID" />
<!-- Create the new "name" attribute. -->
<xsl:attribute name="Name">
<xsl:value-of select="substring-after(@Name, $starting-path)" />
</xsl:attribute>
<!-- Append a backslash to the current path. -->
<xsl:variable name="current-path" select="concat(@Name, '\')" />
<!-- Select all "record" nodes that are one level deeper... -->
<xsl:variable name="children" select="/data/record[
starts-with(@Name, $current-path)
and
not(contains(substring-after(@Name, $current-path), '\'))
]" />
<!-- ...and apply this template to them. -->
<xsl:apply-templates mode="recurse" select="$children">
<xsl:with-param name="starting-path" select="$current-path" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
salida en mi sistema:
<data>
<record ID="26" Name="category 1">
<record ID="24" Name="sub category 1">
<record ID="25" Name="sub category 2"></record>
<record ID="27" Name="sub category 3"></record>
</record>
</record>
</data>
Tenga en cuenta que toda la solución se basa en la suposición de que todos los caminos son canónicos y no contienen barras invertidas de cola .
También tenga en cuenta que los elementos de "registro" no coincidentes/huérfanos no estarán en la salida (a menos que estén en el nivel raíz, por supuesto).
Una cosa más: el modo de plantilla ("recurse") no es estrictamente necesario. Lo incluí porque la plantilla está haciendo algo bastante especial, y podría existir la posibilidad de que exista otra plantilla en su solución que coincida con los nodos "de registro". En este caso, esta solución se puede colocar sin romper nada más. Para una solución independiente, los modos de plantilla se pueden eliminar en cualquier momento.
Ah, y la última cosa: Si desea que el documento resultado de ordenar por nombre, incluya una <xsl:sort>
element con los <xsl:apply-templates>
(ambas ocurrencias), así:
<xsl:apply-templates select="...">
<xsl:sort select="@Name" data-type="text" order="ascending" />
</xsl:apply-templates>
@myso: "sub categoría 3 "está en el mismo nivel que la" subcategoría 2 "en su XML de entrada. No se puede anidar de la manera que se muestra en su XML de salida. – Tomalak
Sí, mi error. Lo he editado – mysomic