Escenario bancario con XSLT

De MediaWiki
Ir a la navegación Ir a la búsqueda

Enunciado

Unha empresa utiliza o seguiente XML para intercambiar información entre bases de datos de distintos proveedores.


Estrutura orixinal:

<!--Estructura original de la información-->
<listado>
    <cuenta>
        <titular dni="5671001D">Ramon Perez</titular>
        <saldoactual moneda="euros">12000</saldoactual>
        <fechacreacion>13-abril-2012</fechacreacion>
    </cuenta>
    <fondo>
        <cuentaasociada>20-A</cuentaasociada>
        <datos>
            <cantidaddepositada>20000</cantidaddepositada>
            <moneda>Euros</moneda>
        </datos>
    </fondo>
    <fondo>
        <cuentaasociada>21-DX</cuentaasociada>
        <datos>
            <cantidaddepositada>4800</cantidaddepositada>
            <moneda>Dolares</moneda>
        </datos>
    </fondo>
    <cuenta>
        <titular dni="39812341C">Carmen Diaz</titular>
        <saldoactual moneda="euros">1900</saldoactual>
        <fechacreacion>15-febrero-2011</fechacreacion>
    </cuenta>
</listado>

Compran un novo sistema que necesita que a información teña a seguinte estrutura.

Estrutura que deben ter os datos:

<!--Estructura final que debemos conseguir-->
<datos>
    <cuentas>
        <cuenta dnititular="5671001D">
            <creacion>13-abril-2012</creacion>
            <titular>Ramon Perez</titular>
            <saldoactual>12000 euros</saldoactual>

        </cuenta>
        <cuenta dnititular="39812341C">
            <creacion>15-febrero-2011</creacion>
            <titular>Carmen Diaz</titular>
            <saldoactual>1900 euros</saldoactual>

        </cuenta>
    </cuentas>
    <fondos>
        <fondo cuentaasociada="20-A">
            <cantidaddepositada>20000</cantidaddepositada>
            <moneda>Euros</moneda>
        </fondo>
        <fondo cuentaasociada="21-DX">
            <cantidaddepositada>4800</cantidaddepositada>
            <moneda>Dolares</moneda>
        </fondo>
    </fondos>
</datos>

Crea o XSLT que permita convertir a información orixinal no novo formato requirido polo sistema.

Análise do problema

Precísanse varios cambios:

  1. Se ha cambiado el nombre de elemento raíz de listado a datos.
  2. Ahora todos los elementos cuenta van dentro de un nuevo elemento cuentas y todos los elementos fondo van dentro de un nuevo elemento fondos.
  3. El dni se ha movido del elemento titular al elemento cuenta.
  4. La fechacreación se ha movido y se ha renombrado a creacion.
  5. El elememento moneda desaparece y su texto se ha puesto al lado de la cantidad que hay en saldoactual.
  6. En el elemento fondo se ha quitado el elemento datos.
  7. El elemento cuentaasociada ha pasado a ser un atributo.

Solución paso a paso

Paso inicial - elemento raíz baleiro

Empecemos por crear una hoja muy básica, que busque el elemento raíz y devuelva como salida el elemento datos (que va a ser la nueva raíz)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
    </datos>
</xsl:template>
</xsl:stylesheet>

Si probamos dicho XSLT aplicándolo al XML original obtendremos esto:

<datos/>

No pasa nada porque se obtenga el elemento raíz vacío, el programa de transformación lo hace para ahorrar tiempo y bytes.

Paso 2. Xenerar elementos cuenta e fondo

Una vez que hemos cambiado el elemento raíz tenemos que generar dos elementos más que agrupen los elementos cuenta y los elementos fondo. Para ello, basta con escribirlos como muestra la siguiente hoja de estilo.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas></cuentas>
        <fondos></fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

[Cuentas]. Paso 1. Movendo elementos cuenta

Primeiro buscamos todos os elementos cuenta e os metemos dentro de cuentas; despois resolveremos o problema dos fondos.

Para percorrer elementos precisamos un bucle for-each. A plantilla sitúase na raíz así que precisaremos o bucle itere por cada un dos elementos de listado/cuenta. Porén, o bucle meterase no elemento fillo listado e vai devolvendo cada un dos elementos cuenta que hai dentro.

Un posible bucle sería este:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta></cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos></fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

Cos nosos datos dará isto como resultado:

<datos>
  <cuentas>
    <cuenta/>
    <cuenta/>
  </cuentas>
  <fondos/>
</datos>

A plantilla xenera dous elementos cuenta, un por cada conta que nos da o bucle. Poderíamos facer isto para ter un nome de elemento distinto. Este será o xeito para poder cambiar de nome un elemento:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <otroelemento></otroelemento>

            </xsl:for-each>
        </cuentas>
        <fondos></fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

[Cuentas]. Paso 2. Meter dentro de atributo dnititular

Sigamos con el problema original: ya hemos creado un elemento cuentas que lleva dentro un elemento cuenta para cada una de las cuentas originales. Ahora en dicho elemento cuenta vamos a meter dentro un atributo llamado dnititular usando la etiqueta xsl:attribute que debe ir dentro del elemento al que le queramos poner el atributo y además al principio. Si queremos varios atributos no pasa nada podemos ponerlos todos dentro del elemento pero recordando ponerlos al principio.

Así, el código siguiente nos fabrica el atributo.


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <!--Esto añade el atributo dnititular a cuenta-->
                    <xsl:attribute name="dnititular">10</xsl:attribute>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos></fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

[Cuentas]. Paso 3. Extraer valor do atributuo dni

Pero hay un problema, todas las cuentas tienen el dnititular a 10. Necesitamos la etiqueta value-of que nos permite extraer el contenido de un elemento o atributo, en este caso queremos extrar el valor del atributo dni que está dentro del elemento titular. Esto se hace con titular/@dni que significa «extraer el atributo dni que debe estar dentro del elemento titular».

Así, el código siguiente:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <xsl:attribute name="dnititular">
                        <xsl:value-of select="titular/@dni"/>
                    </xsl:attribute>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos></fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

Devolve coma resultado:

<datos>
  <cuentas>
    <cuenta dnititular="5671001D"/>
    <cuenta dnititular="39812341C"/>
  </cuentas>
  <fondos/>
</datos>

[Cuentas]. Paso 4. Crear elemento titular

El paso siguiente va a ser crear el elemento titular que también se llama titular en el archivo original. Para ello lo metemos dentro de cuenta y permitiendo que la creación del atributo dnititular se quede al principio.

El código XSLT es este

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <xsl:attribute name="dnititular">
                        <xsl:value-of select="titular/@dni"/>
                    </xsl:attribute>
                    <!--Creamos el elemento titular y metemos
                    dentro del valor original del titular-->
                    <titular>
                        <xsl:value-of select="titular"/>
                    </titular>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos></fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

Que xenera o seguinte resultado:

<datos>
  <cuentas>
    <cuenta dnititular="5671001D">
      <titular>Ramon Perez</titular>
    </cuenta>
    <cuenta dnititular="39812341C">
      <titular>Carmen Diaz</titular>
    </cuenta>
  </cuentas>
  <fondos/>
</datos>

[Cuentas]. Paso 5. Crear elemento saldoactual

Ahora vamos a crear el elemento saldoactual. Dentro de ese elemento debemos escribir el texto que ya tuviese el saldoactual antiguo y escribiendo al lado el atributo moneda.

O código necesario é:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <xsl:attribute name="dnititular">
                        <xsl:value-of select="titular/@dni"/>
                    </xsl:attribute>
                    <!--Creamos el elemento titular y metemos
                    dentro del valor original del titular-->
                    <titular>
                        <xsl:value-of select="titular"/>
                    </titular>
                    <!--Creamos el saldo actual-->
                    <saldoactual>
                        <!--Y metemos dentro la cantidad que tuviese
                        el fichero original...-->
                        <xsl:value-of select="saldoactual"/>
                        <!--Y extraemos la moneda...-->
                         <xsl:value-of select="saldoactual/@moneda"/>
                    </saldoactual>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos></fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

O resultado é este:

<datos>
  <cuentas>
    <cuenta dnititular="5671001D">
      <titular>Ramon Perez</titular>
      <saldoactual>12000euros</saldoactual>
    </cuenta>
    <cuenta dnititular="39812341C">
      <titular>Carmen Diaz</titular>
      <saldoactual>1900euros</saldoactual>
    </cuenta>
  </cuentas>
  <fondos/>
</datos>

[Cuentas]. Paso 7. Engadimos data de creación

Por último, engadimos a data de creación. No ficheiro orixinal chámase:

  • fechacreación

E no ficheiro final chámase creación e vai coma primeiro elemento.

O XSLT sería este:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <xsl:attribute name="dnititular">
                        <xsl:value-of select="titular/@dni"/>
                    </xsl:attribute>
                    <!--Creamos el elemento "creación" que en
                    realidad contiene el texto del elemento
                    "fechacreación" original-->
                    <creacion>
                        <xsl:value-of select="fechacreacion"/>
                    </creacion>
                    <!--Creamos el elemento titular y metemos
                    dentro del valor original del titular-->
                    <titular>
                        <xsl:value-of select="titular"/>
                    </titular>
                    <!--Creamos el saldo actual-->
                    <saldoactual>
                        <!--Y metemos dentro la cantidad que tuviese
                        el fichero original...-->
                        <xsl:value-of select="saldoactual"/>
                        <!--Y extraemos la moneda...-->
                         <xsl:value-of select="saldoactual/@moneda"/>
                    </saldoactual>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos></fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

Que xenera o resultado seguinte:

<datos>
  <cuentas>
    <cuenta dnititular="5671001D">
      <creacion>13-abril-2012</creacion>
      <titular>Ramon Perez</titular>
      <saldoactual>12000euros</saldoactual>
    </cuenta>
    <cuenta dnititular="39812341C">
      <creacion>15-febrero-2011</creacion>
      <titular>Carmen Diaz</titular>
      <saldoactual>1900euros</saldoactual>
    </cuenta>
  </cuentas>
  <fondos/>
</datos>

Así a parte de cuentas que rematada.

[Fondo] Paso 1. Crear elemento fondo

Falta facer o seguinte

  1. Facer un elemento fondos cun bucle que vaia xenerando elementos fondo
  2. Poñer no fondo o atributo cuentaasociada
  3. Crearol elemento cantidaddepositada
  4. Crear o elemento moneda
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <xsl:attribute name="dnititular">
                        <xsl:value-of select="titular/@dni"/>
                    </xsl:attribute>
                    <!--Creamos el elemento "creación" que en
                    realidad contiene el texto del elemento
                    "fechacreación" original-->
                    <creacion>
                        <xsl:value-of select="fechacreacion"/>
                    </creacion>
                    <!--Creamos el elemento titular y metemos
                    dentro del valor original del titular-->
                    <titular>
                        <xsl:value-of select="titular"/>
                    </titular>
                    <!--Creamos el saldo actual-->
                    <saldoactual>
                        <!--Y metemos dentro la cantidad que tuviese
                        el fichero original...-->
                        <xsl:value-of select="saldoactual"/>
                        <!--Y extraemos la moneda...-->
                         <xsl:value-of select="saldoactual/@moneda"/>
                    </saldoactual>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos>
            <xsl:for-each select="listado/fondo">
                <!--Paso 1: crear un fondo por cada fondo original-->
                <fondo>

                </fondo>
            </xsl:for-each>
        </fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

[Fondo] Paso 2. Poner el atributo cuentaasociado

El XSLT sería así:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <xsl:attribute name="dnititular">
                        <xsl:value-of select="titular/@dni"/>
                    </xsl:attribute>
                    <!--Creamos el elemento "creación" que en
                    realidad contiene el texto del elemento
                    "fechacreación" original-->
                    <creacion>
                        <xsl:value-of select="fechacreacion"/>
                    </creacion>
                    <!--Creamos el elemento titular y metemos
                    dentro del valor original del titular-->
                    <titular>
                        <xsl:value-of select="titular"/>
                    </titular>
                    <!--Creamos el saldo actual-->
                    <saldoactual>
                        <!--Y metemos dentro la cantidad que tuviese
                        el fichero original...-->
                        <xsl:value-of select="saldoactual"/>
                        <!--Y extraemos la moneda...-->
                         <xsl:value-of select="saldoactual/@moneda"/>
                    </saldoactual>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos>
            <xsl:for-each select="listado/fondo">
                <!--Paso 1: crear un fondo por cada fondo original-->
                <fondo>
                    <!--Paso 2, crear el atributo cuentaasociada-->
                    <xsl:attribute name="cuentaasociada">
                        <xsl:value-of select="cuentaasociada"/>
                    </xsl:attribute>

                </fondo>
            </xsl:for-each>
        </fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

[Fondo] Paso 3. Crear el elemento cantidaddepositada

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <xsl:attribute name="dnititular">
                        <xsl:value-of select="titular/@dni"/>
                    </xsl:attribute>
                    <!--Creamos el elemento "creación" que en
                    realidad contiene el texto del elemento
                    "fechacreación" original-->
                    <creacion>
                        <xsl:value-of select="fechacreacion"/>
                    </creacion>
                    <!--Creamos el elemento titular y metemos
                    dentro del valor original del titular-->
                    <titular>
                        <xsl:value-of select="titular"/>
                    </titular>
                    <!--Creamos el saldo actual-->
                    <saldoactual>
                        <!--Y metemos dentro la cantidad que tuviese
                        el fichero original...-->
                        <xsl:value-of select="saldoactual"/>
                        <!--Y extraemos la moneda...-->
                         <xsl:value-of select="saldoactual/@moneda"/>
                    </saldoactual>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos>
            <xsl:for-each select="listado/fondo">
                <!--Paso 1: crear un fondo por cada fondo original-->
                <fondo>
                    <!--Paso 2, crear el atributo cuentaasociada-->
                    <xsl:attribute name="cuentaasociada">
                        <xsl:value-of select="cuentaasociada"/>
                    </xsl:attribute>
                    <!--Paso 3, crear el elemento cantidaddepositada-->
                    <cantidaddepositada>
                        <xsl:value-of select="datos/cantidaddepositada"/>
                    </cantidaddepositada>
                </fondo>
            </xsl:for-each>
        </fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

[Fondo] Paso 4. Crear o elemento moneda

O XSLT sería así:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <xsl:attribute name="dnititular">
                        <xsl:value-of select="titular/@dni"/>
                    </xsl:attribute>
                    <!--Creamos el elemento "creación" que en
                    realidad contiene el texto del elemento
                    "fechacreación" original-->
                    <creacion>
                        <xsl:value-of select="fechacreacion"/>
                    </creacion>
                    <!--Creamos el elemento titular y metemos
                    dentro del valor original del titular-->
                    <titular>
                        <xsl:value-of select="titular"/>
                    </titular>
                    <!--Creamos el saldo actual-->
                    <saldoactual>
                        <!--Y metemos dentro la cantidad que tuviese
                        el fichero original...-->
                        <xsl:value-of select="saldoactual"/>
                        <!--Y extraemos la moneda...-->
                         <xsl:value-of select="saldoactual/@moneda"/>
                    </saldoactual>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos>
            <xsl:for-each select="listado/fondo">
                <!--Paso 1: crear un fondo por cada fondo original-->
                <fondo>
                    <!--Paso 2, crear el atributo cuentaasociada-->
                    <xsl:attribute name="cuentaasociada">
                        <xsl:value-of select="cuentaasociada"/>
                    </xsl:attribute>
                    <!--Paso 3, crear el elemento cantidaddepositada-->
                    <cantidaddepositada>
                        <xsl:value-of select="datos/cantidaddepositada"/>
                    </cantidaddepositada>
                    <!--Paso 4:Crear el elemento moneda-->
                    <moneda>
                        <xsl:value-of select="datos/moneda"/>
                    </moneda>
                </fondo>
            </xsl:for-each>
        </fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

Solución final

XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <datos>
        <cuentas>
            <xsl:for-each select="listado/cuenta">
                <cuenta>
                    <xsl:attribute name="dnititular">
                        <xsl:value-of select="titular/@dni"/>
                    </xsl:attribute>
                    <!--Creamos el elemento "creación" que en
                    realidad contiene el texto del elemento
                    "fechacreación" original-->
                    <creacion>
                        <xsl:value-of select="fechacreacion"/>
                    </creacion>
                    <!--Creamos el elemento titular y metemos
                    dentro del valor original del titular-->
                    <titular>
                        <xsl:value-of select="titular"/>
                    </titular>
                    <!--Creamos el saldo actual-->
                    <saldoactual>
                        <!--Y metemos dentro la cantidad que tuviese
                        el fichero original...-->
                        <xsl:value-of select="saldoactual"/>
                        <!--Y extraemos la moneda...-->
                         <xsl:value-of select="saldoactual/@moneda"/>
                    </saldoactual>
                </cuenta>
            </xsl:for-each>
        </cuentas>
        <fondos>
            <xsl:for-each select="listado/fondo">
                <!--Paso 1: crear un fondo por cada fondo original-->
                <fondo>
                    <!--Paso 2, crear el atributo cuentaasociada-->
                    <xsl:attribute name="cuentaasociada">
                        <xsl:value-of select="cuentaasociada"/>
                    </xsl:attribute>
                    <!--Paso 3, crear el elemento cantidaddepositada-->
                    <cantidaddepositada>
                        <xsl:value-of select="datos/cantidaddepositada"/>
                    </cantidaddepositada>
                    <!--Paso 4:Crear el elemento moneda-->
                    <moneda>
                        <xsl:value-of select="datos/moneda"/>
                    </moneda>
                </fondo>
            </xsl:for-each>
        </fondos>
    </datos>
</xsl:template>
</xsl:stylesheet>

Referencias