Generación de archivos PDF a partir de una consulta a SQL Server con XML

 

Fecha: 14/Jul/2005 (13/07/2005)
Autor: Axel Strembel - axel@axel.com.ar

 


En este artículo, la idea es obtener datos desde SQL Server, generar un XML con los mismos para luego escribir un archivo PDF y presentarlo.

Para la generación de PDF, utilizaremos una librería Open Source llamada iTextSharp que pueden obtener desde:

http://itextsharp.sourceforge.net

Una vez que hayamos bajado el fuente o el instalador de la librería, en nuestra aplicación tenemos que hacer referencia al proyecto o, si lo instalamos ya compilado, a la dll que se ha incorporado en el GAC.

El código que presento a continuación es una aplicación de consola en C#.
Para comenzar importaremos los namespaces que necesitamos para trabajar.

using System;
using
System.IO;
using
System.Xml;
using
System.Reflection;
using
System.Data;
using
System.Data.SqlClient;

Los únicos que no hemos utilizado nunca son los de la librería que acabamos de referenciar

using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.xml;

Este último nos permite generar el PDF directamente desde un archivo xml, pero nosotros lo vamos a hacer en el aire.

   
namespace PDFApp
{

Vamos a definir y una clase con un método estático que traiga los datos desde SQLServer y los devuelva a nuestra aplicación como un documento DOM XML para que podamos generar nuestro archivo de resultado.

Nuestro método en cuestión esta sobrecargado por si necesitamos trabajar con transacciones (ya que estamos en el baile, bailemos).

   public class Query
   {
     public static XmlDocument ExecuteQuery(SqlCommand cmd, ref SqlTransaction trans) 
     {
       if( cmd == null )
         throw new ArgumentNullException("cmd", "El comando no puede ser null.");
       if( trans == null )
         throw new ArgumentNullException("trans", "La transaccion no puede ser null.");
 
       XmlNode xmlrow = null;
       XmlReader xmlreader = null;
       XmlDocument xmldoc = null;
       xmldoc = new XmlDocument();
       xmldoc.LoadXml("<ROOT/>");
       xmlreader = cmd.ExecuteXmlReader();
       xmlrow = xmldoc.ReadNode(xmlreader);
       while ( xmlrow != null )
       {
         xmldoc.DocumentElement.AppendChild(xmlrow);
         xmlrow = xmldoc.ReadNode(xmlreader);
       }
       xmlreader.Close();
       return xmldoc;
     }
     public static XmlDocument ExecuteQuery(SqlCommand cmd, SqlConnection conn)
     {
       XmlDocument xmldoc = null;
       SqlTransaction trans = null;
       if ( conn != null ) 
       {
         if ( conn.State != ConnectionState.Open ) 
         {
            conn.Open();
         }
         cmd.Connection = conn;
       }
       else
       {
         throw new ArgumentNullException("cmd", "El comando no puede ser null.");
       }
       trans = cmd.Connection.BeginTransaction();
       xmldoc = new XmlDocument();
       xmldoc.LoadXml("<ROOT/>");
       try       
       {
         cmd.Transaction = trans;
         xmldoc = ExecuteQuery(cmd, ref trans);
         trans.Commit();
       }
       catch (Exception ex) 
       {
         trans.Rollback();
         throw ex;
       }
       return xmldoc;
     }
   }

Aquí empieza lo bueno, vamos a definir nuestra clase con el entry point de la aplicación y generamos el PDF con los resultados.

   class Consola
   {
     [STAThread]
     static void main(string [] args)
     {

A continuación, creamos un objeto document con el tamaño de la pagina y sus márgenes, expresados en floats

       // *******************************************************
       // Generación del documento, aplicando los margenes
       // *******************************************************
       Document document = new Document(PageSize.A4, 90f, 50f, 90f, 60f);
       try 
       {

Pero para generar el PDF vamos a necesitar los datos.
Para ello vamos a llamar al método ExecuteQuery de la clase que definimos antes, la cual nos va a devolver el XML, pasandole los datos que necesite para obtener los datos desde el servidor de base de datos.

         XmlDocument Doc = new XmlDocument();
         SqlConnection cnx = new SqlConnection("Integrated Security=SSPI;Persist Security Info=False;
			Initial Catalog=BASEDEDATOS;Data Source=SERVIDORSQL");
         SqlCommand cmd = new sqlcommand("select * from personas for xml raw"); 

Hay que notar que es muy importante que la consulta desde el motor devuelva XML, para eso incluí en el SQL "FOR XML RAW" para que nuestro amigo SQL Server nos regale los resultados como queremos, asi la clase anterior entiende de que estamos hablando.

         cmd.Connection = cnx;
         Doc = Query.ExecuteQuery(cmd, cnx);

Bien, ya tenemos el XML en el objeto Doc.

Ahora solo tenemos que jugar con los datos para obtener el archivo, pero antes, vamos a decirle a la librería como son algunas de las propiedades que queremos, tales como donde va a escribir el archivo, los tipos de letra, etc, etc.

 

         // *******************************************************
         // Configuración del documento PDF
         // *******************************************************
         string FullPathOut = "c:\\SalidaPDF.pdf";
         PdfWriter.getInstance(document, new filestream(fullpathout, filemode.create));  
         // *******************************************************
         // Fonts y colores
         // ******************************************************* 
         Font font_celdas = FontFactory.getFont(FontFactory.HELVETICA, 8, Font.NORMAL);
         Font font_titulo_tabla = FontFactory.getFont(FontFactory.HELVETICA, 9, Font.BOLD, 
			new Color(255,255,255));
         Color color_negro = new color(0, 0, 0); 

 

Bueno, vamos a ver como mostramos los datos.
Primero tenemos que abrir el documento.

         document.Open();

Ahora vamos a generar una tabla dinámica con algunos de los datos que vamos a obtener.
Yo utilice para el ejemplo, las columnas Nombre, Apellido y Teléfono de la tabla de la base de datos.

         // *******************************************************
         // Tabla
         // ******************************************************* 
         Table table = new Table(3);
         table.BorderWidth = 0;
         table.BorderColor = color_negro;
         table.Padding = 1;
         table.Spacing = 1; 
         Cell titulo = new cell(new Phrase("Datos de la tabla", font_titulo_tabla));
         titulo.Header = true ;
         titulo.BackgroundColor = color_negro;
         titulo.Colspan = 3;
         table.addCell(titulo);
         table.addCell(new Phrase("Nombre", font_celdas));
         table.addCell(new Phrase("Num. Documento", font_celdas));
         table.addCell(new Phrase("Teléfono", font_celdas));
         table.endHeaders();

Como pueden ver, las propiedades para la tabla y para las celdas son muy parecidos a los atributos que definimos en HTML asi que nos vamos a dar cuenta en seguida si necesitamos agregar alguna otra propiedad que querramos.

Ahora vamos a agregar todo lo que nos viene en nuestro XML.

         foreach(xmlelement elem in Doc.SelectNodes("/ROOT/row"))
         {
            table.addCell(new Phrase(Elem.GetAttribute("Usu_Apellido"), font_celdas));
            table.addCell(new Phrase(Elem.GetAttribute("Usu_NroDocumento"), font_celdas));
            table.addCell(new Phrase(Elem.GetAttribute("Usu_Telefono"), font_celdas));
         }

Ya está, ahora solo agreguemos todo esto que generamos a nuestro documento, y.... voala!

         document.Add(table);
       }

Por las dudas.....

       catch (XmlException xex)
       {
         Console.Error.WriteLine(xex.Message);
       }
       catch (DocumentException de) 
       {
         Console.Error.WriteLine(de.Message);
       }
       catch (IOException ioe) 
       {
         Console.Error.WriteLine(ioe.Message);
       }     

Finalmente cerramos todo, no es cuestion de dejar las cosas asi porque si...

       finally
       {
         document.Close();
       }
     }
   }
}

Listo.
Espero que les haya gustado, yo lo utilizo mucho y funciona muy muy bien.
Aparte es muy facil de aprender, en la web de iTextSharp hay mucho material para generar PDF.

Nos vemos.

Axel


Espacios de nombres usados en el código de este artículo:

System
System.IO
System.Xml
System.Reflection
System.Data
System.Data.SqlClient
iTextSharp.text
iTextSharp.text.pdf
iTextSharp.text.xml


ir al índice