xslt fold

¿Cómo doblar por una etiqueta un grupo de etiquetas seleccionadas(vecinas) con XSLT1?



fold (1)

En XSLT 1.0, la técnica estándar para manejar este tipo de cosas se llama agrupación Muenchian, e implica el uso de una clave que define cómo se deben agrupar los nodos y un truco usando generate-id para extraer solo el primer nodo de cada grupo como un proxy para el grupo como un todo.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:strip-space elements="*" /> <xsl:output indent="yes" /> <xsl:key name="elementsByGr" match="*[@gr]" use="@gr" /> <xsl:template match="@*|node()" name="identity"> <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy> </xsl:template> <!-- match the first element with each @gr value --> <xsl:template match="*[@gr][generate-id() = generate-id(key(''elementsByGr'', @gr)[1])]" priority="2"> <fold> <xsl:for-each select="key(''elementsByGr'', @gr)"> <xsl:call-template name="identity" /> </xsl:for-each> </fold> </xsl:template> <!-- ignore subsequent ones in template matching, they''re handled within the first element template --> <xsl:template match="*[@gr]" priority="1" /> </xsl:stylesheet>

Esto logra la agrupación que está buscando, pero al igual que su solución no general, no preserva la indentación y los nodos de texto en blanco entre los elementos a y b , es decir, le dará

<root> <c>cccc</c> <fold> <a gr="g1">aaaa</a> <b gr="g1">1111</b> </fold> <fold> <a gr="g2">bbbb</a> <b gr="g2">2222</b> </fold> </root>

Tenga en cuenta que si pudo usar XSLT 2.0, todo se convierte en uno for-each-group :

<xsl:template match="root"> <xsl:for-each-group select="*" group-adjacent="@gr"> <xsl:choose> <!-- wrap each group in a fold --> <xsl:when test="@gr"> <fold><xsl:copy-of select="current-group()" /></fold> </xsl:when> <!-- or just copy as-is for elements that don''t have a @gr --> <xsl:otherwise> <xsl:copy-of select="current-group()" /> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:template>

Tengo un conjunto de nodos secuenciales que deben incluirse en un nuevo elemento. Ejemplo:

<root> <c>cccc</c> <a gr="g1">aaaa</a> <b gr="g1">1111</b> <a gr="g2">bbbb</a> <b gr="g2">2222</b> </root>

debe estar encerrado por las etiquetas de fold , lo que resulta (después de XSLT) en:

<root> <c>cccc</c> <fold><a gr="g1">aaaa</a> <b gr="g1">1111</b></fold> <fold><a gr="g2">bbbb</a> <b gr="g2">2222</b></fold> </root>

Entonces, tengo una "etiqueta para agrupar" ( @gr ) pero no me imagino cómo producir etiquetas de plegado correctas.

Estoy tratando de usar las pistas de esta pregunta , o esta otra ... Pero tengo una "etiqueta para agrupar", así que entiendo que mi solución no necesita el uso de la función key() .

Mi solución no general es:

<xsl:template match="/"> <root> <xsl:copy-of select="root/c"/> <fold><xsl:for-each select="//*[@gr=''g1'']"> <xsl:copy-of select="."/> </xsl:for-each></fold> <fold><xsl:for-each select="//*[@gr=''g2'']"> <xsl:copy-of select="."/> </xsl:for-each></fold> </root> </xsl:template>

Necesito una solución general (!), Bucle por todos @gr y coping (identidad) todo contexto que no tenga @gr ... quizás usando la transformación de identidad .

Otro problema (futuro) es hacer esto recursivamente, con pliegues de pliegues.