xml - Agrupación XSLT en claves múltiples usando el método Muenchian
xslt-1.0 xslt-grouping (1)
Si el elemento hd1 siempre es ''1234'', entonces no está realmente agrupando por ellos, pero si lo fuera, definiría una clave simple como esa
<xsl:key name="header1" match="AllocFile" use="hd1" />
Para la segunda clave, necesitaría tener en cuenta el elemento Código
<xsl:key name="header2" match="AllocFile" use="concat(hd1, ''|'', Code)" />
Y luego, para la última clave, definiría una clave más complicada para hacer frente a todos los elementos
<xsl:key name="header3"
match="AllocFile"
use="concat(hd1 ''|'', Code, ''|'', G_H, ''|'', FUN, ''|'', oH, ''|'', y)" />
Observe el uso del carácter ''pipa'' como el delimitador. Es importante elegir un delimitado que nunca ocurriría en ninguno de los elementos seleccionados.
Luego, para buscar los distintos elementos header1 , buscará los elementos que aparecen primero en la clave header1
<xsl:apply-templates
select="AllocFile[generate-id() = generate-id(key(''header1'', hd1)[1])]"
mode="header1" />
Para encontrar los distintos elementos de código dentro de cada elemento header1 , harías lo siguiente
<xsl:apply-templates
select="key(''header1'', hd1)
[generate-id() = generate-id(key(''header2'', concat(hd1, ''|'', Code))[1])]"
mode="header2" />
Finalmente, dentro de cada grupo de códigos, para encontrar los distintos elementos ''header3'', buscaría los primeros elementos dentro de la tercera clave
<xsl:apply-templates
select="key(''header2'', concat(hd1, ''|'', Code))
[generate-id() =
generate-id(key(''header3'', concat(hd1, ''|'', Code, ''|'', G_H, ''|'', FUN, ''|'', oH, ''|'', y))[1])]"
mode="header3" />
Aquí está el XSLT completo
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="header1" match="AllocFile" use="hd1"/>
<xsl:key name="header2" match="AllocFile" use="concat(hd1, ''|'', Code)"/>
<xsl:key name="header3" match="AllocFile" use="concat(hd1, ''|'', Code, ''|'', G_H, ''|'', FUN, ''|'', oH, ''|'', y)"/>
<xsl:template match="/XML">
<xsl:apply-templates select="AllocFile[generate-id() = generate-id(key(''header1'', hd1)[1])]" mode="header1"/>
</xsl:template>
<xsl:template match="AllocFile" mode="header1">
<Header1>
<Hd1>
<xsl:value-of select="hd1"/>
</Hd1>
<xsl:apply-templates select="key(''header1'', hd1)[generate-id() = generate-id(key(''header2'', concat(hd1, ''|'', Code))[1])]" mode="header2"/>
</Header1>
</xsl:template>
<xsl:template match="AllocFile" mode="header2">
<CodeHeader>
<xsl:copy-of select="Code"/>
<xsl:apply-templates select="key(''header2'', concat(hd1, ''|'', Code))[generate-id() = generate-id(key(''header3'', concat(hd1, ''|'', Code, ''|'', G_H, ''|'', FUN, ''|'', oH, ''|'', y))[1])]" mode="header3"/>
</CodeHeader>
</xsl:template>
<xsl:template match="AllocFile" mode="header3">
<Header2>
<xsl:copy-of select="G_H|FUN|oH|y"/>
<xsl:apply-templates select="key(''header3'', concat(hd1, ''|'', Code, ''|'', G_H, ''|'', FUN, ''|'', oH, ''|'', y))"/>
</Header2>
</xsl:template>
<xsl:template match="AllocFile">
<allocheader>
<xsl:copy-of select="alc|No|DT|AMOUNT"/>
</allocheader>
</xsl:template>
</xsl:stylesheet>
Tenga en cuenta el uso del atributo de modo en la coincidencia de plantilla para distinguir entre las múltiples plantillas que coinciden con los elementos de AllocFile .
Cuando se aplica al XML de muestra, se muestra el siguiente resultado
<Header1>
<Hd1>1234</Hd1>
<CodeHeader>
<Code>033195</Code>
<Header2>
<G_H>147</G_H>
<FUN>125487</FUN>
<oH>11</oH>
<y>9</y>
<allocheader>
<alc>1</alc>
<No>11/10</No>
<DT>20090401</DT>
<AMOUNT>8000000</AMOUNT>
</allocheader>
<allocheader>
<alc>2</alc>
<No>14/10</No>
<DT>20090401</DT>
<AMOUNT>8400000</AMOUNT>
</allocheader>
<allocheader>
<alc>3</alc>
<No>74/10</No>
<DT>20090401</DT>
<AMOUNT>8740000</AMOUNT>
</allocheader>
</Header2>
</CodeHeader>
<CodeHeader>
<Code>033118</Code>
<Header2>
<G_H>117</G_H>
<FUN>125487</FUN>
<oH>19</oH>
<y>9</y>
<allocheader>
<alc>2</alc>
<No>74/10</No>
<DT>20090401</DT>
<AMOUNT>74512</AMOUNT>
</allocheader>
</Header2>
</CodeHeader>
<CodeHeader>
<Code>033147</Code>
<Header2>
<G_H>117</G_H>
<FUN>125487</FUN>
<oH>19</oH>
<y>9</y>
<allocheader>
<alc>3</alc>
<No>14/10</No>
<DT>20090401</DT>
<AMOUNT>986541</AMOUNT>
</allocheader>
</Header2>
</CodeHeader>
</Header1>
Si tuviera diferentes elementos hd1 , aparte de ''1234'', terminaría con múltiples elementos Header1 , por lo que su salida no sería XML bien formado. Sería lo suficientemente simple como para envolverlos en un elemento raíz aunque modificando la plantilla inicial que coincide con el elemento del documento.
<xsl:template match="/XML">
<Root>
<xsl:apply-templates select="AllocFile[generate-id() = generate-id(key(''header1'', hd1)[1])]" mode="header1" />
</Root>
</xsl:template>
Este es el archivo de entrada.
Todos estos bloques están envueltos en una etiqueta <allocfile>
que no aparece, ¿por qué no? Y todos estos bloques están envueltos en un elemento de nivel superior <xml>
.
<XML>
<AllocFile>
<alc>1</alc>
<No>11/10</No>
<DT>20090401</DT>
<G_H>147</G_H>
<FUN>125487</FUN>
<oH>11</oH>
<y>9</y>
<AMOUNT>8000000</AMOUNT>
<Code>033195</Code>
<hd1>1234</hd1>
</AllocFile>
<AllocFile>
<alc>2</alc>
<No>14/10</No>
<DT>20090401</DT>
<G_H>147</G_H>
<FUN>125487</FUN>
<oH>11</oH>
<y>9</y>
<AMOUNT>8400000</AMOUNT>
<Code>033195</Code>
<hd1>1234</hd1>
</AllocFile>
<AllocFile>
<alc>3</alc>
<No>74/10</No>
<DT>20090401</DT>
<G_H>147</G_H>
<FUN>125487</FUN>
<oH>11</oH>
<y>9</y>
<AMOUNT>8740000</AMOUNT>
<Code>033195</Code>
<hd1>1234</hd1>
</AllocFile>
<AllocFile>
<alc>2</alc>
<No>74/10</No>
<DT>20090401</DT>
<G_H>117</G_H>
<FUN>125487</FUN>
<oH>19</oH>
<y>9</y>
<AMOUNT>74512</AMOUNT>
<Code>033118</Code>
<hd1>1234</hd1>
</AllocFile>
<AllocFile>
<alc>3</alc>
<No>14/10</No>
<DT>20090401</DT>
<G_H>117</G_H>
<FUN>125487</FUN>
<oH>19</oH>
<y>9</y>
<AMOUNT>986541</AMOUNT>
<Code>033147</Code>
<hd1>1234</hd1>
</AllocFile>
</XML>
El resultado es
<Header1>
<Hd1>1234</Hd1>
<CodeHeader>
<Code>033195</Code>
<Header2>
<G_H>147</G_H>
<FUN>125487</FUN>
<oH>11</oH>
<y>9</y>
<allocheader>
<alc>1</alc>
<No>11/10</No>
<DT>20090401</DT>
<AMOUNT>8000000</AMOUNT>
</allocheader>
<allocheader>
<alc>2</alc>
<No>14/10</No>
<DT>20090401</DT>
<AMOUNT>8400000</AMOUNT>
</allocheader>
<allocheader>
<alc>3</alc>
<No>74/10</No>
<DT>20090401</DT>
<AMOUNT>8740000</AMOUNT>
</allocheader>
</Header2>
</CodeHeader>
<CodeHeader>
<Code>033118</Code>
<Header2>
<G_H>117</G_H>
<FUN>125487</FUN>
<oH>19</oH>
<y>9</y>
<allocheader>
<alc>2</alc>
<No>74/10</No>
<DT>20090401</DT>
<AMOUNT>74512</AMOUNT>
</allocheader>
</Header2>
</codeHeader>
<CodeHeader>
<Code>033147</Code>
<Header2>
<G_H>117</G_H>
<FUN>125487</FUN>
<oH>19</oH>
<y>9</y>
<allocheader>
<alc>3</alc>
<No>14/10</No>
<DT>20090401</DT>
<AMOUNT>986541</AMOUNT>
</allocheader>
</Header2>
</CodeHeader>
</Header1>
El archivo de entrada debe ser ordenado y agrupado en base a múltiples claves. Procedí a usar la función concat
y el método Muenchian pero no recibí mucha ayuda de la web. Estoy usando XSLT 1.0.
Reglas para agrupar
Todos los nodos en el archivo tendrán
<hd1>
con los valores1234..
este se convierte en el primer grupo por clave y aparece en la salida como<Header1>
- la segunda clave para agrupar es el código del nodo. los nodos que tienen el mismo valor se agrupan. aparece como. encabezado de código
La segunda clave es el grupo de nodos
G_H
,FUN
,oH
,y
. Si todos estos tienen los mismos valores para los nodos, se agrupan. Aparece en la salida como<Header2>
No ocurre agrupación en los nodos
<alc>
,<No>
,<DT>
,<AMOUNT>
. Ellos tienen valores distintos dentro de cada grupo.