Xml, Html y vb
[Informes con datos guardados en xml, y mostrados en html]

Fecha: 13/03/2003
Autor: José F. Romaniello


Introducción

Muchas veces cuando comenzamos a desarrollar una aplicación somos concientes de su simplicidad, pero aparece siempre la duda de los benditos "informes". Crystal reports, Datareport y algunos otros diseñadores de informes que cuestan cierto dinerillo.

A veces es inentendible como para generar informes tan simple recurrimos a herramientas pagas como "Crystal Report". 

En colaboración con un compañero que he conocido en un curso de programación en tres capas, nos hemos embarcado en la tarea de crear algún método para desarrollar informes simples, con controles gratuitos, y finalmente hemos dado con resultados muy positivos.

Para continuar leyendo este articulo sería importante tener una noción mínima de Xml.

Mezclando y mezclando desarrolle por así decirlo "un modelo" de informes, donde los datos son transportados de una tabla o consulta a un documento XML, y el formato (colores, tipos de letras, etc.) almacenados en un documento Html. Se crea una parte en la aplicación que permite "editar" simplificadamente el contenido del html, sin modificar el origen de datos.

 

Informe Simple

Los controles y clases que he creado no tienen tanta importancia como la forma en que esto se realiza, así que debido a su complejidad, decidí crear una versión más entendible y funcional.

La forma en que se guardan los datos en el Xml es mediante open, write y close del tratamiento de archivos comunes que se realiza con vb.

La estructura del xml es del tipo

<NombreInforme>

    <NombreElemento>

        <Campo1>Contenido</Campo1>

        <Campo2>Contenido</Campo2>

    </NombreElemento>

    <NombreElemento>

        <Campo1>Contenido</Campo1>

        <Campo2>Contenido</Campo2>

    </NombreElemento>

</NombreInforme>

Bien, ahora teniendo los datos en el xml, procedo a contarles acerca de la importación del Xml en un Html. Por ahora lo que he encontrado es bastante "pobre", por que solo funciona para "Ms Internet Explorer", y a veces hace renegar un poco.... Sobre todo por que no existe información acerca de esta funcionalidad del html en ningún editor de html, ni si quiera en el propio "Front Page", que me sorprendió bastante que no tuviera.

Lo que hago es después del tag <body> insertar un tag que abre de alguna manera un origen de datos:

<xml id="Od" src="informe.xml"></xml>

El Id es un identificador que nada tiene que ver con el contenido del documento Xml, y src esta por demás decir que es el nombre y ubicación del fichero Xml.

A continuación colocaremos una tabla de 2 filas y N columnas, donde N es igual a la cantidad de campos que tenga la tabla. Dicha tabla deberá contener una propiedad en el tag <table> que es el "datasrc", este tiene que ser equivalente al nombre del identificador del Xml... es decir:

<table datasrc="#Od" width="100%">

A continuación sigue un tag que le da la característica a la fila 1 de ser cabecera de tabla <thead>, luego va el  <tr> y luego los <th>. Después se cierran en el orden inverso.  Entre <th> y </th> iría el título del campo.

Luego de cerrar thead va el tag <tbody> , <tr> y finalmente <td>. Entre <td> y </td> debe ir :

<span datafld="NombreCampo"></span>

en vez de nombre campo tiene que ir el nombre del campo que aparece en el xml. Y luego se van cerrando los otros dos tags.

De esta manera funciona perfectamente, solo para Internet Explorer.

 

Informes Anidados

Algo muy común son los informes anidados es decir un informe que a su vez tiene subinformes. Tal es el caso de las Cuentas Corrientes o Facturas, donde un Item perteneciente al informe principal esta vinculado con un varios Items de un subinforme (Nro de Movimiento o Nro de factura).

Por ejemplo:

    Nro    Cliente    Fecha    Forma

        Producto    Cantidad    PrecioUnitario

 

A continuación describiré como deben exponerse los datos en cada fichero (Xml, y html), para dotar de esta funcionalidad a nuestros informes.

El Xml debe tener la siguiente estructura:

<NombreInforme>

    <NombreElemento>

        <Campo1>Contenido</Campo1>

        <Campo2>Contenido</Campo2>

        <SubElemento>

            <SubCampo1>Contenido</SubCampo1>

            <SubCampo1>Contenido</SubCampo1>

        </SubElemento>

        <SubElemento>

            <SubCampo1>Contenido</SubCampo1>

            <SubCampo1>Contenido</SubCampo1>

        </SubElemento>

    </NombreElemento>

    <NombreElemento>

        <Campo1>Contenido</Campo1>

        <Campo2>Contenido</Campo2>

    </NombreElemento>

        <SubElemento>

            <SubCampo1></SubCampo1>

            <SubCampo1></SubCampo1>

        </SubElemento>

</NombreInforme>

Cada elemento puede tener N subelementos, donde N puede valer 0 en dicho caso debe escribirse como si fuera un solo subelemento sin ningún contenido. 

A esta altura del artículo cabe destacar que los elementos por mas que estén contenidos dentro de otro elemento, deben siempre tener el mismo nombre, mientras que los campos finales, que poseen "el contenido" deben tener nombres diferentes en un mismo elemento, para que el Xml este "bien formado".

Con respecto al documento html debe ser igual al ejemplo sin anidar, solo que en vez de ser de 2 filas y N columnas, debe tener 3 filas. 

La tercera fila solo tendrá una columna y debe contener otra tabla mas en su interior, y en el tag <table> además de la propiedad datasrc apuntando al identificador del xml, la propiedad datafld con el nombre del subelemento. 

Para el ejemplo de xml anterior:

<table datasrc="#Od" datafld="SubElemento" width="100%">

Y nuevamente se repite todo lo explicado para la primera tabla.

 

Salto de página

Puede ser necesario algunas veces crear un salto de página cada N registros. El salto de página en html puede ser provocado mediante la siguiente etiqueta: 

<div style="page-break-before:always"></div>

Solo para Internet Explorer.

Podemos agregarle un campo a los elementos del Xml y al html (pero invisible), que sea nulo y en el registro que queremos provocar el salto el código antes mencionado.

 

Quitar encabezado y pie de páginas automáticos del Iexplorer

Al momento de imprimir puede dotar de "calidad" a nuestros informes que no salgan los encabezados y pie de página que el IExplorer tiene por defecto. 

Ya sea haciendo que no se imprima nada o que se imprima algo personalizado.

Para no hacer demasiado extenso el artículo solo diré que dichas características se encuentran en el registro de Windows en: 

"Software\Microsoft\Internet Explorer\PageSetup"

(si alguien necesita las funciones explicitas para modificar el registro en estas direcciones mandarme un mail)

Primero deben guardarse en algunas variables el contenido de estas, luego modificarlo, luego la impresión, y cuando regresa al proyecto, restaurar el valor anterior.

 

Algo de Vb

A continuación sigue código en Visual Basic:

Private Function GuardarDInf(strInforme As String, rsRecordset As ADODB.Recordset)
    'se recibe el nombre del informe en singular, (no plural)
    'por ejemplo; strinforme = "cliente",
    'y un recordset ya abierto de la tabla clientes.
    Dim i As Integer
    
    Open strInforme & ".xml" For Output As fXml
    'se abre el archivo xml en cuestión, para el ejemplo "cliente.xml"
        
        Escribir "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?> "
        'se escribe el tag de descripción del xml
        
        Escribir Eq1(strInforme & "s")
        'se escribe el elemento 'madre' del xml
        'para el ejemplo "<clientes>"
        'cabe destacar que todos los demas elementos pertenecen
        'a <clientes>
        
        With rsRecordset
            Do While Not .EOF
            'recorremos la tabla
            
                Escribir Eq1(strInforme)
                'abrimos un elemento
                '<cliente>
                
                For i = 0 To .Fields.Count - 1
                'recorremos todos los campos de dicho registro
                
                    Escribir Eq1(.Fields(i).Name) & .Fields(i).Value & Eq2(.Fields(i).Name)
                    'abrimos el nombre del campo, escribimos el contenido
                    ', y cerramos el nombre del campo
                    '<Id>124</Id>
                    
                Next i
                
                Escribir Eq2(strInforme)
                'cerramos el elemento
                '</cliente>
            Loop
        End With
        
        Escribir Eq2(strInforme & "s")
        'cerramos el elemento madre
        
    Close fXml
    'cerramos el xml
    
    Ejecutar strInforme & ".html"
    'finalmente, o lo mostramos en algun objeto webbrowser de nuestra app.
    
End Function

Public Function Eq1(ByVal strCadena As String) As String
Eq1 = "<" & Trim(strCadena) & ">"
End Function

Public Function Eq2(ByVal strCadena As String) As String
Eq2 = "</" & Trim(strCadena) & ">"
End Function

Public Function Escribir(ByVal strCadena As String)
Print #fXml, strCadena
End Function

Nota: el código expuesto anteriormente no debe ser copiado y pegado "intacto", puede contener incoherencias, solo lo expongo como ejemplo de lo sencillo que puede ser la creación del Xml.

Espero que les haya sido interesante el artículo y ojala me manden sugerencias y comentarios a mi mail. 

El archivo zip que adjunto debe ser descomprimido todo en la misma carpeta.

El contendi de dicho archivo es el siguiente:

Clientes.html Ejemplo de informe simple.
Clientes.xml Origen de datos del ejemplo de informe simple.
ClientesA.html Ejemplo de informe anidado.
ClientesA.xml Origen de datos del ejemplo de informe anidado.
Module1.bas Módulo para cambiar el encabezado y pie de página.

xmlhtmlvb.zip


ir al índice