viernes, 18 de diciembre de 2009

Mucho de XSL

XSL

La utilización de XSL nos ha dado mucha facilidad para la generación de código, ya sea html o cualquier código como puede ser PDF o una trasformación de un SDT a otro, lo que precisemos.
Basándonos como entrada en un XML(Datos) y generando a partir de él lo que se nos ocurra. Independizando los datos de entrada de la presentación o formato de salida.



Primeramente mostraremos una presentación general sobre el uso de XSL, luego algunos ejemplos de cosas generadas con XSL, así como también como utlizarlo para enriquecer nuestras aplicaciones con genexus.

Generalidades sobre el USO de XSL

Qué es?
  * XSL :  Extensible Stylesheet Languaje
  * Es un lenguaje basado en XML que permite la transformación, conversión o formateo de documentos XML
  * Es un lenguaje, con sentencias y comandos
  * Lo particular es que la sintaxis respeta el formato XML
  * Partiendo de una entrada en XML se genera mediante el XSL una salida cualquiera
  * Se puede generar por ejemplo: HTML, Javascript, XML, o lo que se nos ocurra

Para qué sirve?

Sirve para realizar transformaciones de documentos XML hacia otros formatos, como puede ser HTML, XML, archivos de texto planos, o lo que se desee

Ventajas

  * Podemos independizar los datos de la presentación
  * Uso de los SDTs en varios lugares del sistema con distinta forma de mostrarlos y personalizables para cada cliente si fuese necesario
  * Podemos generar formatos livianos de presentación y estandarizados

Cómo se usa?

  * Dado un XML con un formato específico, se programa un XSL que contemple ese formato y la unión del XML con el XSL, mediante un programa de transformación genera el resultado
  * Esta unión se llama transformación por lo que al XML le aplicamos una transformación mediante un XSL y obtenemos por ejemplo un HTML


En GeneXus

  * Desde GX podemos usarlo de manera sencilla
  * Desde la versión 9.0 agregó el método XSLTApply para las variables del tipo string.
  * &HTMLResult = &XML.XSLTApply(&XSLFormateo)


Me sirve?

  * A mi mucho!
  * Pero eso se evalúa cada vez que tenemos que trabajar con DATOS y mostrarlos
  * Deberíamos tener presente esta herramienta
  * Da soluciones a problemas que de otra manera generan mucho hardcode o soluciones POCO mantenibles, amigables y personalizables


Conclusión

  * Es una herramienta más con bastantes prestaciones
  * Muchas veces es muy útil, otras no tanto
  * La decisión de cuándo, cómo y para qué lo usan y si lo usan :) es de ustedes

Hola Mundo (bajar)

XML
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml:stylesheet type="text/xsl" href="holamundo.xsl"?>
<saludo>
        Hola Mundo!
</saludo>

XSL
<?xml version='1.0' encoding='iso-8859-1'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
    <html>
        <STYLE>
            .miestilo
            {   
                font-weight : bolder;
                font-size: 3.2em;
                font-family: arial;
                text-align: center;   
                text-shadow: 3px 3px 7px #111;           
                v-Align: center;
                border-style:groove;
                border-width:2px;
                border-color:gray;
            }
        </STYLE>
        <body leftMargin="2" rightMargin="2" topMargin="2" bottomMargin="2">   
            <xsl:apply-templates select="saludo"/>           
        </body>       
    </html>           
</xsl:template>

<xsl:template match="saludo">
<!-- Tabla principal -->
    <table>
        <tr>
            <td>
                <span class="miestilo"><b><xsl:value-of select="."/></b></span>   
            </td>           
        </tr>
    </table>
</xsl:template>

</xsl:stylesheet>

Inicio (bajar)

XML

<?xml version="1.0" encoding="iso-8859-1"?>
<?xml:stylesheet type="text/xsl" href="inicio.xsl"?>
<personas>
    <persona>
        <nombre>Elmas</nombre>
        <apellido>Grande</apellido>
        <edad>119</edad>
        <campeon>SI SI SI!!</campeon>
        <cuadro>Peñarol</cuadro>        
        <cuadroa>Peñarol</cuadroa>
    </persona>   
    <persona>
        <nombre>Elhijo</nombre>
        <apellido>Desiempre</apellido>
        <edad>109</edad>
        <campeon>NO NO NO!!</campeon>
        <cuadro>Nacional</cuadro>                
    </persona>
</personas>   

XSL

<?xml version='1.0' encoding='iso-8859-1'?>
<xsl:stylesheet
 version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<html>
    <style>   
        .estilonombre
            {   
                font-weight : bolder;
                font-size: 25;
                font-family: verdana;
                background-color: lightgray;               
            }
            .etiqueta
            {   
                font-weight : bolder;               
            }
            .estilocuadro
            {   
                font-weight : bolder;
                font-size: 25;
                font-family: arial;
                color: white;
                background-image:url('penarol.png');
                text-align: center;               
                v-Align: center;
                border-style:groove;
                border-width:2px;
                border-color:gray;
            }
            .estilotabla
            {   
                border-style:groove;
                border-width:2px;
                border-color:gray;
            }       
    </style>
    <body leftMargin="2" rightMargin="2" topMargin="2" bottomMargin="2">   
        <xsl:apply-templates select="personas"/>
    </body>       
</html>           
</xsl:template>

<xsl:template match="personas">
    <xsl:apply-templates select="persona"/>
</xsl:template>

<xsl:template match="persona">
<!-- Tabla principal -->
<table class="estilotabla">
    <tbody>   
    <tr>
        <td rowspan="2">
            <xsl:choose>
                <xsl:when test="cuadro/text()='Peñarol'">
                    <img src="penarol.jpeg"/>
                </xsl:when>   
                <xsl:when test="cuadro/text()='Nacional'">
                    <img src="nacional.jpeg"/>
                </xsl:when>
            </xsl:choose>
        </td>
        <td>
            <table>
                <tr>
                    <td>
                        <xsl:apply-templates select="nombre"/>
                    </td>
                    <td>
                        <xsl:apply-templates select="apellido"/>
                    </td>
                </tr>
            </table>
        </td>
    </tr>
    <tr>   
        <td>       
            <table>
                <tr>
                    <td>
                        <span class="etiqueta">Edad:</span>
                    </td>
                    <td>
                        <xsl:apply-templates select="edad"/>                                       
                        <xsl:if test="edad/text()&lt;=25">
                            <span>Un Pibe! (<b>las masitas?</b>)</span>
                        </xsl:if>
                    </td>
                </tr>
                <tr>
                    <td>
                        <span class="etiqueta">Campeón:</span>
                    </td>
                    <td>
                        <xsl:apply-templates select="campeon"/>
                    </td>
                </tr>
                <tr>
                    <td>
                        <span class="etiqueta">El corazón:</span>
                    </td>
                    <td>
                        <xsl:apply-templates select="cuadro"/>                                       
                    </td>
                </tr>           
            </table>
        </td>                                       
    </tr>
    </tbody>           
</table>   
   
</xsl:template>
       
<xsl:template match="nombre">   
    <span class="estilonombre"><xsl:value-of select="."/></span>
</xsl:template>

<xsl:template match="apellido">   
    <span class="estilonombre"><xsl:value-of select="."/></span>       
</xsl:template>

<xsl:template match="edad">   
    <span><xsl:value-of select="."/></span>       
</xsl:template>

<xsl:template match="campeon">   
    <span><xsl:value-of select="."/></span>       
</xsl:template>

<xsl:template match="cuadro">   
    <span class="estilocuadro"><xsl:value-of select="."/></span>   
</xsl:template>

</xsl:stylesheet>


Ejemplos de HTML Generados con XSL




Menú desplegable de Acciones (bajar)



Mapa de Acciones (bajar)



Organigrama (bajar)


Historia de Expediente (bajar)



Deudas (bajar)



Navegación de páginas (bajar)

Categorización en Grid (bajar)




Exportacion a Excel  (bajar)
(genera un html que se abre con excel)





Registro estructurado en Bandeja de Entrada  (bajar)



Alertas (bajar)








Ejemplo de Arbol de Categorías de Materiales (bajar)

En este ejemplo, a partir de un xml generado recursivamente con un procedimiento genexus, utilizando un SDT, cuya definición mostraremos más adelante, obtenemos un html con estructura de árbol, colapsable por nodos. La intención al mostrar este ejemplo es ver como podemos independizar los datos de la visualización de manera muy sencilla. A su vez, utilizando javascript podemos permitir acciones y enriquecer la presentación.

XML

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml:stylesheet type="text/xsl" href="categorias.xsl"?>
<SDTCategoriasArbol >
    <Categorias>
        <Categoria>
            <Codigo>5</Codigo>
            <Descripcion>Azulejos</Descripcion>
            <Nivel>1</Nivel>
            <Materiales>
                <Material>
                    <Codigo>3</Codigo>
                    <Descripcion>Material 1</Descripcion>
                    <Nivel>2</Nivel>
                </Material>
                <Material>
                    <Codigo>4</Codigo>
                    <Descripcion>nuevo material</Descripcion>
                    <Nivel>2</Nivel>
                </Material>
            </Materiales>
        </Categoria>
        <Categoria>
            <Codigo>9</Codigo>
            <Descripcion>Material de Obra</Descripcion>
            <Nivel>1</Nivel>
            <Categorias>
                <Categorias>
                    <Categoria>
                        <Codigo>4</Codigo>
                        <Descripcion>Pisos</Descripcion>
                        <Nivel>2</Nivel>
                        <Categorias>
                            <Categorias>
                                <Categoria>
                                    <Codigo>1</Codigo>
                                    <Descripcion>Madera</Descripcion>
                                    <Nivel>3</Nivel>
                                </Categoria>
                                <Categoria>
                                    <Codigo>3</Codigo>
                                    <Descripcion>Cerámicas</Descripcion>
                                    <Nivel>3</Nivel>
                                    <Categorias>
                                        <Categorias>
                                            <Categoria>
                                                <Codigo>12</Codigo>
                                                <Descripcion>Alto tránsito</Descripcion>
                                                <Nivel>4</Nivel>
                                            </Categoria>
                                            <Categoria>
                                                <Codigo>13</Codigo>
                                                <Descripcion>Bajo trásito</Descripcion>
                                                <Nivel>4</Nivel>
                                            </Categoria>
                                        </Categorias>
                                    </Categorias>
                                </Categoria>
                            </Categorias>
                        </Categorias>
                    </Categoria>
                </Categorias>
            </Categorias>
            <Materiales>
                <Material>
                    <Codigo>5</Codigo>
                    <Descripcion>Porland</Descripcion>
                    <Nivel>2</Nivel>
                </Material>
            </Materiales>
        </Categoria>
        <Categoria>
            <Codigo>6</Codigo>
            <Descripcion>Medidas</Descripcion>
            <Nivel>1</Nivel>
            <Materiales>
            </Materiales>
        </Categoria>
        <Categoria>
            <Codigo>7</Codigo>
            <Descripcion>Pinturas</Descripcion>
            <Nivel>1</Nivel>
            <Materiales>
            </Materiales>
        </Categoria>
        <Categoria>
            <Codigo>10</Codigo>
            <Descripcion>Sanitaria</Descripcion>
            <Nivel>1</Nivel>
            <Categorias>
                <Categorias>
                    <Categoria>
                        <Codigo>8</Codigo>
                        <Descripcion>Caños</Descripcion>
                        <Nivel>2</Nivel>
                        <Categorias>
                            <Categorias>
                                <Categoria>
                                    <Codigo>2</Codigo>
                                    <Descripcion>Hierro</Descripcion>
                                    <Nivel>3</Nivel>
                                    <Categorias>
                                        <Categorias>
                                            <Categoria>
                                                <Codigo>11</Codigo>
                                                <Descripcion>Alta Calidad</Descripcion>
                                                <Nivel>4</Nivel>
                                            </Categoria>
                                        </Categorias>
                                    </Categorias>
                                </Categoria>
                            </Categorias>
                        </Categorias>
                    </Categoria>
                </Categorias>
            </Categorias>
            <Materiales>
            </Materiales>
        </Categoria>
    </Categorias>
</SDTCategoriasArbol>


XSL 


***********Código***********

<?xml version='1.0' encoding='iso-8859-1'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
    <html>
        <head>
            <script type="text/javascript" src="categorias.js"></script>
            <style>
            .Titulo
            {
                color: #977659;           
                font-family: Verdana;
                font-size: 13pt;
                font-style: normal;
                font-variant: normal;
                font-weight:bold;
                text-decoration: none;
                text-shadow: 2px 2px 4px #4AB7D7;
                cursor:pointer;
            }
            .Categoria
            {
                color: #087184;           
                font-family: Verdana;
                font-size: 10pt;
                font-style: normal;
                font-variant: normal;
                font-weight:bold;
                text-decoration: none;
                text-shadow: 2px 2px 4px #4AB7D7;
                cursor:pointer;
            }   
            .Material
            {
                color: #977659;           
                font-family: Verdana;
                font-size: 10pt;
                font-style: normal;
                font-variant: normal;
                font-weight:bold;
                text-decoration: none;
                text-shadow: 2px 2px 4px #4AB7D7;
                cursor:pointer;
            }   
            </style>           
        </head>
        <body>
            <xsl:apply-templates select="SDTCategoriasArbol"/>
        </body>
    </html>   
</xsl:template>

<xsl:template match="SDTCategoriasArbol">
    <table align="left" cellpadding="0" cellspacing="0">
        <tr>
            <td>
                <span class="Titulo">Materiales por Categoría</span>
            </td>
        </tr>
        <tr height="20px">
            <td>
               
            </td>
        </tr>
        <tr>
            <xsl:apply-templates select="Categorias"/>           
        </tr>
    </table>
</xsl:template>

<xsl:template match="Categorias">
   
    <xsl:apply-templates select="Categoria"/>
   
</xsl:template>

<xsl:template match="Categoria">
    <tr>
    <td>
        <xsl:attribute name="style">
            padding-left:<xsl:value-of select="Nivel/."/>0;
        </xsl:attribute>
        <table align="left" cellpadding="0" cellspacing="0">           
            <tr>
                <td>
                    <xsl:if test="Nivel/. > 1">
                        <img src="arbollinea.gif"/>                       
                    </xsl:if>
                    <xsl:if test="Nivel/. = 1">
                        <img src="sig.png"/>
                    </xsl:if>
                </td>
                <td valign="top">
                    <span class="Categoria">
                        <xsl:attribute name="title">Cód: <xsl:value-of select="Codigo/."/></xsl:attribute>
                        <xsl:attribute name="style">
                            <xsl:if test="Nivel/. mod 2 = 0">
                                color:#379DBA;
                            </xsl:if>                           
                        </xsl:attribute>
                        <xsl:attribute name="onclick">javascript:verocultar('Id_<xsl:value-of select="Codigo/."/>')</xsl:attribute>
                        <xsl:value-of select="Descripcion/."/>
                    </span>   
                </td>
            </tr>
            <xsl:if test="Nivel/. = 1">
                <tr height="5px">
                    <td>
                    </td>
                    <td>
                    </td>
                </tr>
            </xsl:if>
            <tr>
                <td>
                   
                </td>
                <td>
                    <div>
                        <xsl:attribute name="style">visibility:visible;display:inline;position:relative;</xsl:attribute>
                        <xsl:attribute name="id">Id_<xsl:value-of select="Codigo/."/></xsl:attribute>
                        <table align="left" cellpadding="0" cellspacing="0" >   
                            <xsl:apply-templates select="Categorias/Categorias"/>
                            <xsl:apply-templates select="Materiales"/>           
                        </table>   
                    </div>
                </td>               
            </tr>           
        </table>
    </td>
    </tr>
</xsl:template>   

<xsl:template match="Materiales">   
    <xsl:apply-templates select="Material"/>
   
</xsl:template>
   
   
<xsl:template match="Material">
    <tr>
    <td>
        <xsl:attribute name="style">
            padding-left:<xsl:value-of select="Nivel/."/>0;
        </xsl:attribute>
        <table align="left" cellpadding="0" cellspacing="0">           
            <tr>
                <td>
                    <xsl:if test="Nivel/. > 1">
                        <img src="arbollinea.gif"/>                       
                    </xsl:if>
                    <xsl:if test="Nivel/. = 1">
                        <img src="sig.png"/>
                    </xsl:if>
                </td>
                <td valign="top">
                    <span class="Material">
                        <xsl:attribute name="title">Cód: <xsl:value-of select="Codigo/."/> (<xsl:value-of select="Unidad/."/>)</xsl:attribute>
                        <xsl:value-of select="Descripcion/."/>
                    </span>   
                </td>
            </tr>
            <xsl:if test="Nivel/. = 1">
                <tr height="5px">
                    <td>
                    </td>
                    <td>
                    </td>
                </tr>
            </xsl:if>
            <tr>
                <td>
                   
                </td>
                <td>
                   
                </td>               
            </tr>           
        </table>
    </td>
    </tr>
</xsl:template>   
   
</xsl:stylesheet>





***********Fin Código***********


Obs: 
  • Se podría también tener un css para la definición de estilos, sería más prolijo y generaría un grado más de independiencia entre datos y presentación.
 
Desde GeneXus como hago?

SDT




Procedimiento Recursivo y sus particularidades

En este ejemplo, el procedimiento genera un mapa con todas las categorías que hay definidas, recursivamente, dado que todas ellas hacen referencias al padre.
El procedimiento principal  retorna el nombre del archivo generado (un html) y los errores ocurridos.

Guarda en disco el html para accederlo luego desde la aplicción y también guarda el xml generado (el sdt) con algunas modificaciones. Esto fue una decisión para este caso. En muchos otros casos directamente el procedimiento devuelve en un longvarchar el html generado y se muestra en un webpanel con una variable o textblock con formato html.

Procedimiento Principal ( OCategoriaXML )

Rules

parm(out:&Filename, out:&ErrorMessage );

Source

***********Código***********
 

&SDTCategorias = new SDTCategoriasArbol()
&SDTCategorias.Categorias.Clear()

for each OCategoriaMatPadre OCategoriaMatDescripcion
    where OCategoriaMatPadre = 0
    defined by OCategoriaMatDescripcion
    &Nivel = 1
    &Categoria = new SDTCategoriasArbol.Categoria()
    &Categoria.Codigo = OCategoriaMatCodigo
    &Categoria.Descripcion = OCategoriaMatDescripcion   
    &Categoria.Nivel = &Nivel
   
    OCategoriaXMLRecursivo.Call(OCategoriaMatCodigo, &Nivel ,&Categoria )
   
    &Categoria.Materiales.Clear()   
    for each
        defined by OMaterialDescripcion
        &Material = new SDTCategoriasArbol.Categoria.Material()
        &Material.Codigo = OMaterialCodigo
        &Material.Descripcion = OMaterialDescripcion
        &Material.Unidad = OUnidadDescripcion
        &Material.Nivel = &Nivel + 1
        &Categoria.Materiales.Add(&Material )           
    endfor
    &SDTCategorias.Categorias.Add(&Categoria )   
endfor

&XMLResult = &SDTCategorias.ToXml()

//Obtengo datos desde par�metros
call(GeoParametrosReportes, &XSLPath ,&ExcelPath ,&ExcelRelativePath ,&NameSpace )

&Respuesta = '<?xml version="1.0" encoding="UTF-8"?>' + &SDTCategorias.ToXml()
&Reemplazar = 'xmlns="' + &NameSpace.Trim() + '"'
&Respuesta = &Respuesta.Replace( &Reemplazar  , "")
&HTML = &Respuesta.XSLTApply(&XSLPath.Trim() + 'categorias.xsl')

&Random = Random() * 10000

////////Archivo XML

&File = &PgmName.Trim() + !"-" + &Random.ToString().Trim() + !".xml"
   
&FilePath = &ExcelPath.Trim() + &File
&Filename = &ExcelRelativePath.Trim() + &File

&XMLWriter.Open(&FilePath )

&XMLWriter.WriteRawText(&SDTCategorias.ToXml() )
&XMLWriter.Close()

////////Archivo HTML

&File = &PgmName.Trim() + !"-" + &Random.ToString().Trim() + !".html"
   
&FilePath = &ExcelPath.Trim() + &File
&Filename = &ExcelRelativePath.Trim() + &File

&XMLWriter.Open(&FilePath )

&XMLWriter.WriteRawText(&HTML )
&XMLWriter.Close()

***********Fin Código***********
 

Procedimiento Recursivo ( OCategoriaXMLRecursivo )

Rules

parm(in:OCategoriaMatPadre ,in:&Nivel, inout:&Categoria );

Source

***********Código***********
 


&NivelActual = &Nivel + 1
for each OCategoriaMatPadre
    defined by OCategoriaMatDescripcion
   
    &CategoriaHija = new SDTCategoriasArbol.Categoria()
    &CategoriaHija.Codigo = OCategoriaMatCodigo
    &CategoriaHija.Descripcion = OCategoriaMatDescripcion   
    &CategoriaHija.Nivel = &NivelActual
   
    OCategoriaXMLRecursivo.Call(OCategoriaMatCodigo, &NivelActual ,&CategoriaHija )
   
    &Categoria.Categorias.Categorias.Add(&CategoriaHija )   
endfor

***********Fin Código***********


 JS

***********Código***********
 

function verocultar(tableID)
{
    var tab = document.getElementById(tableID);
    if (tab.style.visibility == "hidden")
    {
        verocultarrec(tab, "show");
    }
    else
    {
        verocultarrec(tab, "hide");
    }
}
function verocultarrec(tab, op)
{   
    if (tab.style != null && tab.id != null )
    {
        if (op == "show")
        {
            tab.style.position="relative";                       
            tab.style.visibility="visible";   
           
            oItems = tab.getElementsByTagName("div");
            for (var index = 0; index < oItems.length; index++)
               {
                   oItems[index].style.position="relative";                       
                oItems[index].style.visibility="visible";               
               }
           
        }   
        else               
        {
            tab.style.position="absolute";   
            tab.style.visibility="hidden";
           
            oItems = tab.getElementsByTagName("div");
            for (var index = 0; index < oItems.length; index++)
               {
                   oItems[index].style.position="absolute";   
                oItems[index].style.visibility="hidden";              
               }   
              
        }   
    }
   
}


***********Fin Código***********


Cómo se ve en ejecución?