¿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.