Unos tips de XSLT 1.0
En ocasiones es necesario dedicarle tiempo a los XSLTs que se ocupan en la composición de Servicios. Esto, debido a que, operaciones sobre la información del cuerpo del mensaje, se pueden hacer a través de Transformaciones, y descargar un poco la carga en la orquestación (BPEL).
Pensemos que se tiene el siguiente mensaje:
<?xml version="1.0" encoding="UTF-8" ?>
<REGISTROS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://rcarrasco.org/ejemplo file:/C:/JDeveloper/xsd/ejemplos/ejemplo.xsd" xmlns="http://rcarrasco.org/ejemplo">
<REGISTRO>
<CUENTA>CUENTA1</CUENTA>
<FECHA>FECHAVALOR41</FECHA>
<FOLIO>-0</FOLIO>
<TRANS>TRANSACCION42</TRANSACCION>
<TIPODEMOVIMIENTO>N</TIPODEMOVIMIENTO>
<IMPORTE>10</IMPORTE>
</REGISTRO>
<REGISTRO>
<CUENTA>CUENTA1</CUENTA>
<FECHA>FECHAVALOR41</FECHA>
<FOLIO>-0</FOLIO>
<TRANS>TRANSACCION42</TRANSACCION>
<TIPODEMOVIMIENTO>M</TIPODEMOVIMIENTO>
<IMPORTE>10</IMPORTE>
</REGISTRO>
<REGISTRO>
<CUENTA>CUENTA2</CUENTA>
<FECHA>FECHAVALOR41</FECHA>
<FOLIO>-0</FOLIO>
<TRANS>TRANSACCION42</TRANSACCION>
<TIPODEMOVIMIENTO>N</TIPODEMOVIMIENTO>
<IMPORTE>10</IMPORTE>
</REGISTRO>
<CUENTA>CUENTA3</CUENTA>
<FECHA>FECHAVALOR41</FECHA>
<FOLIO>-0</FOLIO>
<TRANS>TRANSACCION42</TRANSACCION>
<TIPODEMOVIMIENTO>N</TIPODEMOVIMIENTO>
<IMPORTE>10</IMPORTE>
</REGISTRO>
</REGISTROS>
De este mensaje, queremos hacer un equivalente de SELECT DISTINCT de SQL. Para diferenciar las CUENTAS que vienen en el mensaje, y poder agruparlas de esa manera.
Para esto, podemos basarnos en el Muenchian Method, que sirve muy bien en la versión 1.0 de XSLT. Ya en la 2.0, existen algunas capacidades mas directas para hacer agrupaciones.
(Para mayor referencia a este método, vean esto http://our.umbraco.org/forum/developers/xslt/16581-Muenchian-method-question)
De manera que nuestra hoja de estilo/transformación podría lucir de la siguiente manera, si buscamos diferenciar las CUENTAS del documento XML en cuestión:
<xsl:key name="CUENTA-key" match="/tns:REGISTROS/tns:REGISTRO"
use="tns:CUENTA/text()"/>
<xsl:template match="/">
<client:insertaHeaderLines>
<xsl:variable name="bankName"
<client:HEADER>
<xsl:for-each select="tns:REGISTROS/tns:REGISTRO[generate-id() = generate-id(key('CUENTA-key', tns:CUENTA/text()))]">
Primero, generamos un key, que nos servirá para la expresión de diferenciación.
Posteriormente, en el for-each, pondemos la expresión:
tns:REGISTROS/tns:REGISTRO[generate-id() = generate-id(key('CUENTA-key', tns:CUENTA/text()))]
Con ésto, podemos diferenciarlas.
Ahora, supongamos que necesitamos sumar y contar, los IMPORTES de cada grupo de Cuentas. Podemos usar las siguientes variables, adentro del for-each:
<xsl:for-each select="tns:REGISTROS/tns:REGISTRO[generate-id() = generate-id(key('CUENTA-key', tns:CUENTA/text()))]">
<xsl:variable name="CONTROL_M"
select="sum(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = M and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
<xsl:variable name="CONTROL_M_COUNT"
select="count(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = M and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
<xsl:variable name="CONTROL_N"
select="sum(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = N and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
<xsl:variable name="CONTROL_N_COUNT"
select="count(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = N and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
<xsl:variable name="TOTAL_IMPORTE"
select="sum(../tns:REGISTRO[tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
Vemos como con la siguiente expresión, logramos sumar y agrupar:
<xsl:variable name="CONTROL_N"
select="sum(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = N and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
Otra función interesante, que es parte de las extensiones de Oracle para expresiones XPATH, es la siguiente:
oraext:query-database(“query”,false(),false(),”connectionString ó JNDI”)
Esta función te permite incorporar consultas de Base de datos en tus transformaciones, o bien expresiones XPATH.
Aquí un ejemplo:
oraext:query-database(“select * fom dual ”,false(),false(),”jdbc:oracle:thin:scott/tiger@localhost:1521:orcl”)
También pueden pasar parámetros en el query. Pero eso se los puedo pasar en un email.
Pensemos que se tiene el siguiente mensaje:
<?xml version="1.0" encoding="UTF-8" ?>
<REGISTROS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://rcarrasco.org/ejemplo file:/C:/JDeveloper/xsd/ejemplos/ejemplo.xsd" xmlns="http://rcarrasco.org/ejemplo">
<REGISTRO>
<CUENTA>CUENTA1</CUENTA>
<FECHA>FECHAVALOR41</FECHA>
<FOLIO>-0</FOLIO>
<TRANS>TRANSACCION42</TRANSACCION>
<TIPODEMOVIMIENTO>N</TIPODEMOVIMIENTO>
<IMPORTE>10</IMPORTE>
</REGISTRO>
<REGISTRO>
<CUENTA>CUENTA1</CUENTA>
<FECHA>FECHAVALOR41</FECHA>
<FOLIO>-0</FOLIO>
<TRANS>TRANSACCION42</TRANSACCION>
<TIPODEMOVIMIENTO>M</TIPODEMOVIMIENTO>
<IMPORTE>10</IMPORTE>
</REGISTRO>
<REGISTRO>
<CUENTA>CUENTA2</CUENTA>
<FECHA>FECHAVALOR41</FECHA>
<FOLIO>-0</FOLIO>
<TRANS>TRANSACCION42</TRANSACCION>
<TIPODEMOVIMIENTO>N</TIPODEMOVIMIENTO>
<IMPORTE>10</IMPORTE>
</REGISTRO>
<CUENTA>CUENTA3</CUENTA>
<FECHA>FECHAVALOR41</FECHA>
<FOLIO>-0</FOLIO>
<TRANS>TRANSACCION42</TRANSACCION>
<TIPODEMOVIMIENTO>N</TIPODEMOVIMIENTO>
<IMPORTE>10</IMPORTE>
</REGISTRO>
</REGISTROS>
De este mensaje, queremos hacer un equivalente de SELECT DISTINCT de SQL. Para diferenciar las CUENTAS que vienen en el mensaje, y poder agruparlas de esa manera.
Para esto, podemos basarnos en el Muenchian Method, que sirve muy bien en la versión 1.0 de XSLT. Ya en la 2.0, existen algunas capacidades mas directas para hacer agrupaciones.
(Para mayor referencia a este método, vean esto http://our.umbraco.org/forum/developers/xslt/16581-Muenchian-method-question)
De manera que nuestra hoja de estilo/transformación podría lucir de la siguiente manera, si buscamos diferenciar las CUENTAS del documento XML en cuestión:
<xsl:key name="CUENTA-key" match="/tns:REGISTROS/tns:REGISTRO"
use="tns:CUENTA/text()"/>
<xsl:template match="/">
<client:insertaHeaderLines>
<xsl:variable name="bankName"
<client:HEADER>
<xsl:for-each select="tns:REGISTROS/tns:REGISTRO[generate-id() = generate-id(key('CUENTA-key', tns:CUENTA/text()))]">
Primero, generamos un key, que nos servirá para la expresión de diferenciación.
Posteriormente, en el for-each, pondemos la expresión:
tns:REGISTROS/tns:REGISTRO[generate-id() = generate-id(key('CUENTA-key', tns:CUENTA/text()))]
Con ésto, podemos diferenciarlas.
Ahora, supongamos que necesitamos sumar y contar, los IMPORTES de cada grupo de Cuentas. Podemos usar las siguientes variables, adentro del for-each:
<xsl:for-each select="tns:REGISTROS/tns:REGISTRO[generate-id() = generate-id(key('CUENTA-key', tns:CUENTA/text()))]">
<xsl:variable name="CONTROL_M"
select="sum(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = M and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
<xsl:variable name="CONTROL_M_COUNT"
select="count(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = M and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
<xsl:variable name="CONTROL_N"
select="sum(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = N and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
<xsl:variable name="CONTROL_N_COUNT"
select="count(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = N and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
<xsl:variable name="TOTAL_IMPORTE"
select="sum(../tns:REGISTRO[tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
Vemos como con la siguiente expresión, logramos sumar y agrupar:
<xsl:variable name="CONTROL_N"
select="sum(../tns:REGISTRO[tns:TIPODEMOVIMIENTO = N and tns:CUENTA = current()/tns:CUENTA]/tns:IMPORTE)"/>
Otra función interesante, que es parte de las extensiones de Oracle para expresiones XPATH, es la siguiente:
oraext:query-database(“query”,false(),false(),”connectionString ó JNDI”)
Esta función te permite incorporar consultas de Base de datos en tus transformaciones, o bien expresiones XPATH.
Aquí un ejemplo:
oraext:query-database(“select * fom dual ”,false(),false(),”jdbc:oracle:thin:scott/tiger@localhost:1521:orcl”)
También pueden pasar parámetros en el query. Pero eso se los puedo pasar en un email.
Publicar un comentario