jueves, julio 03, 2008

Motor de Informes Dinámicos con itextsharp (II)

Hola de nuevo a todos, ha pasado un tiempo desde la primera parte del tutorial, pero ya he encontrado tiempo para escribir esta segunda parte (más interesante que la primera). En la primera parte vimos cómo funcionaba la librería itext# para generar informes PDF al vuelo. En esta segunda parte lo que veremos será cómo crear plantillas XML para juntarlas posteriormente con datos y generar el PDF.

El inicio de todo
Lo que vamos a hacer es por un lado, crearnos una plantilla XML con parámetros, por otro lado, generar nuestros datos en formato XML (para poder guardarlos en base de datos) y finalmente, juntar las dos cosas y obtener, al vuelo, la plantilla con los datos en formato PDF.

El flujo de datos

El funcionamiento del sistema de plantillas es el siguiente.

















Desde la página obtenemos los datos en XML y la plantilla, lo cual va en sesión a la página ImpresionPDF.aspx. Esa página se encarga de llamar a la clase ParseadorPDF.cs que es la que contiene la lógica de negocio para generar el PDF al vuelo. Esa clase devuelve un MemoryStream con el PDF a la página, la cual lo renderizará en pantalla.

La plantilla XML
El primer paso es generarnos la plantilla XML con los tags adecuados que entienda la librería. Para un ejemplo de los tags que se pueden utilizar, en la ayuda nos ofrecen algunos ejemplos. Nosotros vamos a trabajar con el siguiente XML que es muy sencillo:






















En este informe utilizamos diferentes tags, como: table, row, cell, newline, itext(obligatorio al inicio y al fin) y en medio hemos introducido tags propios:nomAE, numAE, nomAl y dniAl. Estos serán los parámetros que se sustituirán posteriormente por los valores que le digamos. La librería itextsharp tiene un problema a la hora de parsear los XML en PDFs y es que NO PUEDE TENER ESPACIOS EN BLANCO DENTRO DE LOS TAGS TABLES. Es decir, para generar una plantilla XML, no podemos indentarla, sino que tiene que ir como se muestra en la imagen o dará un error de ejecución.

Los datos a parsear
En este paso, lo que vamos a ver es cómo pasarle los datos que queremos que aparezcan en el informe a la librería para que los junte correctamente. Le vamos a pasar un vector con dos dimensiones, en una dimensión irá un esquema XML con los datos a imprimir y en la otra irá la plantilla a utilizar. El esquema XML es como el siguiente:













A la hora de crear el documento veremos cómo crear este esquema XML para guardarlo en base de datos. Una vez recuperado el documento XML, la creación del vector es la siguiente:








En el vector de objetos “datos” guardamos el XML y la plantilla correspondiente. Seguidamente llamamos a la pantalla ImpresionPDF.aspx que se encargará de generar la plantilla XML.


La página ImpresionPDF.aspx

Esta página es la encargada de recibir los datos desde la sesión y llamar a la clase encargada de generar el PDF. Además de esto, obtiene de base de datos los márgenes a aplicar, las dimensiones del PDF y varios datos de formato propios de la plantilla. Una vez recuperados estos datos llama al método GenerarPDF de la clase ParseadorPDF:








El método devuelve un MemoryStream con el fichero PDF para ser renderizado. Veamos ahora cómo se produce el parseo real de los datos.


La clase ParseadorPDF.cs

Esta es la clase que se encarga de juntar las plantillas con sus respectivos datos. El flujo es el siguiente:

1. Crear el PDF global que va a ser devuelto y ponerle las dimensiones precisas:






2. Recorrer los datos y plantillas pasadas para ir tratando a cada una de ellas. Este método permite que se pasen a la vez varios XML de datos con varias plantillas en el mismo vector de objetos, por lo que lo primero es ir recorriendo las diferentes plantillas. Para cada XML de datos realizamos una conversión a un vector de objects con los datos que es lo que entiende el método:






3. Para cada plantilla con sus datos los juntamos en un PDF temporal que es guardado en una ruta temporal y posteriormente anexado al PDF global que se creó al inicio. En esta parte es donde se realiza la unión real de los datos, creando un hashtable que enlaza cada parámetro con su valor y llamando al método Parse de la librería PDF:












4. Una vez realizado el parseo, lo que tenemos que hacer es eliminar los ficheros temporales que hemos ido creando en el proceso. Estos ficheros se encuentran guardados en la variable subFicheros.

El método ParsearDatos

Este método es el encargado de crear un hashtable que enlace cada parámetro con su valor. Lo primero es crear el hashtable y asignarle los primeros valores fijos:














Seguidamente, para cada parámetro, tendremos que unirlo con su parámetro y asignarle un XMLPeer correcto:











Dependiendo del tipo de parámetro que sea será tratado de una forma o de otra, lo que rellenamos en el método es la propiedad peer.Content con el valor del parámetro y si le queremos incluir más atributos rellenamos la propiedad peer.AddValue.


El método ConcatenarPaginas

Este método se encarga de unir las páginas de los PDF temporales que creamos con la del PDF global que será devuelto a la capa de presentación. El código de este método es el siguiente:












El final

Bueno, con esto termino el artículo. Espero haberos dado una idea inicial de cómo realizar un motor de plantillas basado en XML para la librería itextsharp. No he podido explicar el funcionamiento completo porque eso exigiría muchísimo tiempo pero creo haber ahondado bastante para que podáis seguir vosotros.


Como siempre, para cualquier duda que os surja aquí estoy.


2 comentarios:

Nacho Foche dijo...

Nene, ¿y con una hoja de estilo XSLT no podrías parsear los datos XML de un plumazo y pasarlos rápidamente a PDF?

Por cierto, una entrada genial, dentro de poco prometo terminar ya con las de diseño de redes inalámbricas que te tengo abandonao :).

Manuel Cardenas Thorlund dijo...

Básicamente, la estrategia es la misma, al final, lo que se obtiene con ambos métodos es un XML con las variables rellenas para lanzar el método Parser a PDF. El algoritmo que está puesto es un poco más complejo porque en lo que lo utilizamos lanzamos impresiones de varias plantillas a la vez con lo que tenemos que tenerlo en cuenta. En el próximo post (o el siguiente) voy a explicar cómo utilizar el FCKEditor para crearnos las plantillas de forma dinámica y fácil.