lunes, 5 de marzo de 2007

Creación de Informes Word de Listas de SharePoint

Todos conocemos las bondades de SharePoint, pero a pesar de tener toda la información que se pueda desear bien almacenada y organizada y de las herramientas de filtro, búsqueda, vistas y demás, se sigue queriendo tener un informe en papel para distribuir, anotar, leer, etc.
Para solventar esa ‘necesidad’ de imprimir de los usuarios se puede crear una aplicación de escritorio para generar informes de las listas que nos interesen. Para ello crearemos una aplicación Windows Form en la que usaremos los WebService que nos brinda SharePoint y el modelo de objetos de Microsoft Word.


Primero deberemos obtener los elementos de la lista que nos interesa. Para usar el WebService que nos hace falta debemos agregar una referencia web a nuestro proyecto, para ello pulsamos con el botón derecho en “Referencias Web” y seleccionamos agregar. En la zona URL ponemos “http://spserver/_vti_bin/lists.asmx” (donde spserver es la ruta del sitio donde se halla la lista que nos interesa) y cambiamos el nombre de referencia web por “WSList” para que nos sea más fácil a la hora de programar. También deberemos añadir los espacios de nombres System.Net y System.Xml para poder implementar el siguiente método:

public bool obtenerElementos()
{
  try
  {
    WSList.Lists lista = new WSList.Lists();
    lista.Credentials = new NetworkCredential(usuario, password, dominio);

    lista.Url = "http://spserver/_vti_bin/lists.asmx";

    XmlDocument xmlDoc = new XmlDocument();
    XmlNode nodeQ = xmlDoc.CreateNode(XmlNodeType.Element, "Query","");
    XmlNode nodeVF = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields","");
    XmlNode nodeQO = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions","");

    XmlNode xmlNode = lista.GetListItems("Noticias",null,nodeQ,nodeVF,null,nodeQO);

    string xpathQuery = "//*[local-name() = 'data' and namespace-uri() = 'urn:schemas-microsoft-com:rowset']/*[local-name() = 'row' and namespace-uri() = '#RowsetSchema']";

    noticias = xmlNode.SelectNodes(xpathQuery);

    return true;
  }
  catch(Exception ex)
  {
    return false;
  }
}

Con este método ya tenemos almacenados los elementos de nuestra lista de Noticias en un objeto XmlElement que lo declararemos de forma global para la aplicación. Ahora solo queda crear el informe en Word.

Para poder crear un informe en Word deberemos primero agregar unas referencias a nuestro proyecto. Para ello seleccionamos agregar nueva referencia y en la pestaña COM seleccionamos “Microsoft Word Object Library” y la agregamos.

Para poder implementar el método hemos de poner en nuestro código la llamada a la librería de Word, using Word = Microsoft.Office.Interop.Word. Y el código de nuestro método para generar un informe en Word es:
public string crearInformeWord()
{
/* Creamos la aplicacion word y el documento */
Word._Application oWord;
  Word._Document oDoc;
  oWord = new Word.Application();

  for(int i=0; i'<'noticias.Count; i++)
  {
    try
    {
      object oMissing = System.Reflection.Missing.Value;
/* \endofdoc es un bookmark predefinido
* para el final del documento */
      object oEndOfDoc = "\\endofdoc";

/* Creamos un nuevo documento de Word */
      oDoc = oWord.Documents.Add(ref oMissing,ref oMissing,ref oMissing,ref oMissing);
      object oRng;

/* Creamos el párrafo para insertar el titulo */
Word.Paragraph oParrafoTitulo;

/* Establecemos la referencia del parrafo
* al final del documento */
      oRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
      oParrafoTitulo = oDoc.Content.Paragraphs.Add(ref oRng);

/* El texto del párrafo será el título de la noticia */
      oParrafoTitulo.Range.Text = noticias[i].Attributes[“ows_Title”].Value;
      oParrafoTitulo.Range.Font.Name = "Tahoma"; //Fuente de la letra
      oParrafoTitulo.Range.Font.Size = 12; //Tamaño de la letra
      oParrafoTitulo.Range.Font.Bold = 1; //Negrita SI/NO
      oParrafoTitulo.Format.SpaceAfter = 12; //Espacio con el parrafo siguiente
      oParrafoTitulo.Range.InsertParagraphAfter(); //Inserta el párrafo

/* Creamos el párrafo para insertar el cuerpo */
      Word.Paragraph oParrafoCuerpo;

/* Establecemos la referencia del parrafo al final del documento */
      oRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
      oParrafoCuerpo = oDoc.Content.Paragraphs.Add(ref oRng);

/* El texto del párrafo será la descripción de la noticia */
      oParrafoCuerpo.Range.Text = noticias[i].Attributes[“ows_Descripcion”].Value;
      oParrafoCuerpo.Range.Font.Name = "Tahoma"; //Fuente de la letra
      oParrafoCuerpo.Range.Font.Size = 10; //Tamaño de la letra
      oParrafoCuerpo.Range.Font.Bold = 0; //Negrita SI/NO
      oParrafoCuerpo.Format.SpaceAfter = 6; //Espacio con el parrafo siguiente
      oParrafoCuerpo.Range.InsertParagraphAfter(); //Inserta el párrafo

/* Salto de página para poner una noticia en cada página del informe
* Solo saltamos de página si no es la última noticia */
      if(i+1 < noticias.Count)
      {
        Word.Paragraph oParaSalto;
        oRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
        oParaSalto = oDoc.Content.Paragraphs.Add(ref oRng);
        object oPageBreak = Word.WdBreakType.wdPageBreak;
        oParaSalto.Range.InsertBreak(ref oPageBreak);
      }

    }
    catch(Exception ex)
    {
/* Muy importante ponerlo también en el catch
* Ya que si falla y no se pone Word queda abierto en segundo plano */
      oWord.Visible = true;
    }
  }
}

También podemos generar una tabla con todas las noticias:

public string crearTablaWord()
{
/* Creamos la aplicación Word y el documento */
  Word._Application oWord;
  Word._Document oDoc;
  oWord = new Word.Application();

  try
  {
/* Calculo del numero de filas
* para poner en cada fila dos noticias (2 columnas) */
    int filas = 1;

    if(noticias.Count%2 == 1)
    {
      filas = (noticias.Count/2)+1;
    }
    else
    {
      filas = noticias.Count/2;
    }

/* Creamos el objeto tabla */
    Word.Table oTable;

/* Establecemos la posición al final del documento */
    Word.Range wrdRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;

/* Indicamos el numero de filas y columnas */
    oTable = oDoc.Tables.Add(wrdRng, filas, 2, ref oMissing, ref oMissing);
    oTable.Range.ParagraphFormat.SpaceAfter = 6;
    oTable.Columns.Borders.Enable = 1; //ponemos bordes a la tabla
oTable.Range.Font.Bold = 0;

/* Agregamos el texto a las celdas */
    int r, c, pos;
    pos = 0;
    string text;
    for(r = 1; r '<'= filas; r++)
    {
      for(c = 1; c '<'= 2; c++)
      {
/* Controlamos si en la última celda no se va a escribir nada */
      if(r==filas && c==2)
      {
        text = "Título: ";
        oTable.Cell(r, c).Range.Text = text;
        text = "Autor: ";
        oTable.Cell(r, c).Range.Text += text;
        text = "Creado: ";
        oTable.Cell(r, c).Range.Text += text;
      }
      else
      {
/* Ponemos el titulo, autor y fecha de creación de la noticia */
          text = "Título: "+ noticias[pos].Attributes["ows_title"].Value;
          oTable.Cell(r, c).Range.Text = text;
          text = "Autor: "+ noticias[pos].Attributes["ows_Author"].Value;
          oTable.Cell(r, c).Range.Text += text;
          text = "Creado: "+ noticias[pos].Attributes["ows_Created"].Value;
          oTable.Cell(r, c).Range.Text += text;
        }

        pos++;
      }
    }
  }
  catch(Exception ex)
  {
/* Muy importante ponerlo también en el catch ya que si falla
* y no se pone, Word queda abierto en segundo plano */

    oWord.Visible = true;
  }

  oWord.Visible = true;
}

Si queremos que nuestro informe quede mejor, podemos crear una plantilla de Word con un encabezado y pie de página, donde podremos poner un logo, número de páginas, etc y crear el informe a partir de esa plantilla. Para hacer esto solo habrá que cambiar lo siguiente al principio del método:

/* Hay que cambiar esto */
oDoc = oWord.Documents.Add(ref oMissing, ref oMissing, ref oMissing, ref oMissing);

/* Por esto otro */
object oPlantilla = "c:\\plantilla.dot";
oDoc = oWord.Documents.Add(ref oPlantilla,ref oMissing,ref oMissing, ref oMissing);

Con esto tenemos un generador de informes de cualquier lista de SharePoint que a más de un usuario le puede interesar.

No hay comentarios: