Está en la página 1de 20

Generar libros de Excel 2010 mediante el

SDK de Open XML 2.0


Office 2010

Resumen: aprenda a usar Open XML SDK 2.0 para manipular un libro de Microsoft Excel
2010.

Última modificación: jueves, 05 de enero de 2012

Hace referencia a: Excel 2010 | Office 2010 | Open XML | SharePoint Server 2010 | VBA

Se aplica a: Microsoft Excel 2010

Publicado: abril de 2011

Proporcionado por: Steve Hansen, Grid Logic

Contenido

 Introducción al formato de archivo Open XML


 Examinar un archivo de Excel
 Manipular archivos Open XML mediante programación
 Manipular libros con Open XML SDK 2.0
 Conclusión
 Recursos adicionales
 Acerca del autor

Descargar el código de ejemplo (en inglés)

Introducción al formato de archivo Open XML

Open XML es un formato de archivo abierto para las aplicaciones principales de Office,
orientadas a documentos. Open XML representa de manera fiel documentos de
procesamiento de texto, presentaciones y hojas de cálculo existentes y codificados en
formato binario según las aplicaciones de Microsoft Office. Los formatos de archivo Open
XML ofrecen varias ventajas. Una ventaja es que con los formatos de archivo Open XML
cualquier programa que entienda el formato del archivo puede tener acceso a los datos
contenidos en el documento. De este modo, las organizaciones tienen la seguridad de que
los documentos que crean hoy seguirán siendo válidos en el futuro. Otra ventaja es que
facilita la creación de documentos y la manipulación en entornos de servidor u otros
entornos en los que no se pueden instalar aplicaciones cliente de Office.
Como indica el nombre, los archivos Open XML se representan mediante XML. No
obstante, en lugar de representar un documento usando un único archivo XML grande, un
documento Open XML se representa en realidad usando un conjunto de archivos
relacionados, denominados partes, que se almacenan en un paquete que después se
comprime en un archivo ZIP. Los paquetes de documentos Open XML son compatibles con
la especificación Open Packaging Conventions (Convenciones de empaquetado abierto,
OPC), una tecnología de archivo-contenedor que sirve para almacenar una combinación de
archivos XML y no XML que en su conjunto forman una entidad única.

Examinar un archivo de Excel

Una de las mejoras maneras de empezar a comprender cómo funciona todo en conjunto es
abrir un archivo de libro y examinar sus partes. Para estudiar las partes de un paquete de
libro de Microsoft Excel 2010, basta con cambiar la extensión del nombre del archivo .xlsx
por .zip. Vea el ejemplo del libro mostrado en las figuras 1 y 2.

Figura 1. Libro sencillo

Este libro contiene dos hojas de cálculo: en la figura 1 se muestra una hoja de cálculo que
contiene las ventas anuales y en la figura 2 se muestra una hoja de cálculo que contiene un
gráfico sencillo.

Figura 2. Gráfico básico en un libro


Si cambia el nombre de este libro Simple Sales Example.xlsx por Simple Sales
Example.zip, podrá examinar la estructura de las partes del paquete o contenedor del
archivo con el explorador de Windows.

Figura 3. Estructura de las partes de un libro sencillo


En la figura 3, se muestran las carpetas principales del interior del paquete junto con las
partes almacenadas en la carpeta Worksheets. Profundizando un poco, en la figura 4, se
muestra el XML que se encuentra en la parte denominada sheet1.xml.

Figura 4. Ejemplo del XML dentro de una parte de la hoja de cálculo

El XML mostrado en la figura 4 proporciona la información que Excel necesita para


representar la hoja de cálculo mostrada en la figura 1. Por ejemplo, en el nodo sheetData
hay nodos de fila. Hay un nodo de fila por cada fila que tiene al menos una celda que no
está vacía. Y, en cada fila, hay un nodo para cada celda que no está vacía.

Observe que la celda C3 mostrada en la figura 1 contiene el valor 2008 en negrita. En


cambio, la celda C4 contiene el valor 182 con el formato predeterminado y sin negrita. La
representación de XML de cada una de estas celdas se muestra en la figura 4. En particular,
el XML de la celda C3 se muestra en el ejemplo siguiente.

XML
Copiar
<c r="C3" s="1">
<v>2008</v>
</c>

Para mantener el tamaño de los archivos Open XML lo más pequeño posible, muchos de
los nodos y atributos de XML tienen nombres muy cortos. En el fragmento anterior, c
representa una celda. Esta celda determinada especifica dos atributos: r (Referencia) y s
(Índice de estilos). El atributo de referencia especifica una referencia de ubicación para la
celda.

El índice de estilos es una referencia al estilo que se usa para dar formato a la celda. Los
estilos se definen en la parte de estilo (styles.xml) que se encuentra en la carpeta xl (vea la
carpeta xl en la figura 3). Compare el XML de la celda C3 con el de la celda C4 mostrado
en el ejemplo siguiente.

XML
Copiar
<c r="C4">
<v>182</v>
</c>

Como la celda C4 usa el formato predeterminado, no es necesario especificar un valor para


el atributo de índice de estilos. Más adelante, en este artículo, aprenderá algo más sobre
cómo usar los índices de estilo en un documento Open XML.

Aunque es muy útil saber más sobre las peculiaridades del formato de archivos Open XML,
la finalidad última de este artículo es mostrar cómo usar Open XML SDK 2.0 para
Microsoft Office para manipular mediante programación los documentos Open XML, en
particular, los libros de Excel.

Manipular archivos Open XML mediante programación

Un modo de crear o manipular documentos Open XML mediante programación es usar el


siguiente patrón general:

1. Abrir/crear un paquete Open XML


2. Abrir/crear las partes del paquete
3. Analizar el XML de las partes que debe manipular
4. Manipular el XML a su conveniencia
5. Guardar la parte
6. Volver a empaquetar el documento

Todos estos pasos, salvo el tres y el cuatro, pueden realizarse fácilmente usando las clases
que se encuentran en el espacio de nombres System.IO.Packaging. Estas clases están
pensadas para facilitar el trabajo con los paquetes y tareas de Open XML asociados con la
manipulación de partes en general.
El paso más complicado de este proceso es el cuarto, la manipulación del XML. Para este
paso es absolutamente necesario que el desarrollador conozca todos los tediosos detalles
necesarios para trabajar satisfactoriamente con las numerosas peculiaridades que presentan
los formatos de archivo Open XML. Por ejemplo, antes hemos aprendido que la
información de formato de una celda no se almacena con la celda, sino que la información
detallada de formato se define como estilo en una parte de documento diferente y que el
índice de estilos asociado con el estilo es lo que Excel almacena en la celda.

Incluso con un conocimiento profuso de la especificación Open XML, muchos


desarrolladores no se sienten cómodos con la idea de tener que manipular mediante
programación XML sin formato. Aquí es donde Open XML SDK 2.0 entra en escena.

Open XML SDK 2.0 se desarrolló para facilitar la manipulación de los paquetes Open
XML y los elementos de esquema Open XML subyacentes en el interior del paquete. Open
XML SDK 2.0 encapsula muchas tareas comunes que los desarrolladores realizan en los
paquetes Open XML de modo que en lugar de trabajar con XML sin formato, puede usar
las clases de .NET que le proporcionan muchas ventajas durante el diseño, como
compatibilidad con IntelliSense y desarrollo con seguridad de tipos.

Nota
Descargue Open XML SDK 2.0 del Centro de descarga de Microsoft.

Manipular libros con Open XML SDK 2.0

Con el objeto de mostrar cómo se manipula un libro de Excel con Open XML SDK 2.0,
este artículo explica cómo crear un generador de informes. Imagine que trabaja para una
agencia de valores y bolsa denominada Contoso. El sitio web ASP.NET de Contoso
permite a los clientes conectarse y ver en línea informes sobre algunas carteras. No
obstante, los usuarios solicitan con frecuencia poder ver o descargar los informes en Excel
para realizar otros análisis específicos en las carteras.

Nota
Para que pueda probar fácilmente este código usted mismo, en el ejemplo siguiente se crea
una aplicación basada en la consola. Dicho esto, las técnicas que se usan en este ejemplo
serían 100% compatibles con un sitio web ASP.NET. En ningún momento, se necesita
Microsoft Excel en este ejemplo.

El resultado que se intenta conseguir es un proceso que genere un informe de cartera en


Excel para un cliente determinado. Hay dos estrategias para realizar este tipo de
procedimiento. Una es generar todos los documentos desde cero. Para los libros sencillos
sin formato o con poco formato, esta es la estrategia adecuada. La segunda es crear
documentos que usen una plantilla; este es, normalmente, el método preferido. Observe
que, en este caso, el uso de una plantilla de Word no se refiere a las plantillas reales de
Excel (*.xltx), sino al uso de un libro (*.xlsx) que contiene el formato, los gráficos y demás
elementos que se desean incluir en el libro definitivo. Para usar la plantilla, primero debe
realizar una copia de esta y, después, debe agregar los datos asociados con el cliente para el
que está creando un informe.

Figura 5. Ejemplo de informe de cartera

Configurar el proyecto

Para crear un generador de informes de cartera, abra Microsoft Visual Studio 2010 y cree
una aplicación de consola denominada PortfolioReportGenerator.

Nota
Para descargar los proyectos de C# y .NET Visual Basic de ejemplo, haga clic en
Descargue el código de ejemplo (en inglés).
Figura 6. Crear una solución de generador de informes de cartera
A continuación, agregue dos clases al proyecto: PortfolioReport y Portfolio. La clase
PortfolioReport es la clase clave que realiza toda la manipulación del documento con Open
XML SDK 2.0. La clase Portfolio es básicamente una estructura de datos que contiene las
propiedades necesarias para representar una cartera de cliente.

Nota
La clase Portfolio se detalla en este cambio. Es un contenedor de datos con algunos datos
de prueba y no tiene código relacionado con Open XML ni Open XML SDK 2.0.

Antes de escribir el código, lo primero que debe hacerse en un proyecto donde se usen
Open XML y Open XML SDK 2.0 es agregar las referencias necesarias al proyecto. Se
necesitan dos referencias específicas: DocumentFormat.OpenXml y WindowsBase.

DocumentFormat.OpenXml contiene las clases que se instalan con Open XML SDK 2.0. Si
no puede encontrar esta referencia después de instalar Open XML SDK 2.0, puede buscarla
con el explorador. De forma predeterminada, se encuentra en C:\Archivos de programa
(x86)\Open XML SDK\V2.0\lib\. Esta referencia solo es necesaria si tiene la intención de
usar Open XML SDK 2.0. Si va a manipular los documentos Open XML modificando el
XML sin formato, no necesitará esta referencia.
WindowsBase incluye las clases del espacio de nombres System.IO.Packaging. Esta
referencia es necesaria en todos los proyectos Open XML sin importar si Open XML SDK
2.0 se usa o no. Las clases del espacio de nombres System.IO.Packaging proporcionan
funciones para abrir paquetes Open XML. Además, hay clases que permiten manipular
(agregar, eliminar, editar) partes del interior de un paquete Open XML.

En este punto, su proyecto debería parecerse al de la figura 7.

Figura 7. Proyecto Generador de informes de cartera tras su configuración inicial

Inicializar el informe de cartera

Como hemos mencionado, el proceso de generación de informes empieza creando una


copia de la plantilla de informe y agregando datos al informe. La plantilla de informe es un
libro de Excel, con un formato predefinido, denominado PortfolioReport.xlsx. Agregue un
constructor a la clase PortfolioReport que realiza este proceso. A fin de copiar el archivo,
también debe importar el espacio de nombres System.IO. Al tiempo que agregue el espacio
de nombres System.IO, agregue los espacios de nombres relacionados con Open XML
SDK 2.0.

C#
Copiar
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml;

namespace PortfolioReportGenerator
{
class PortfolioReport
{
string path = "c:\\example\\";
string templateName = "PortfolioReport.xlsx";

public PortfolioReport(string client)


{
string newFileName = path + client + ".xlsx";
CopyFile(path + templateName, newFileName);
}

private string CopyFile(string source, string dest)


{
string result = "Copied file";
try
{
// Overwrites existing files
File.Copy(source, dest, true);
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
}
}

Tenga en cuenta que el constructor PortfolioReport requiere un solo parámetro que


represente al cliente para el que se está generando el informe.

Para no tener que pasar parámetros a los métodos ni tener que volver a abrir
constantemente el documento y extraer la parte de libro, agregue dos variables privadas de
ámbito de clase a la clase PortfolioReport. De la misma manera, agregue una variable
privada de ámbito de clase para mantener una referencia al objeto Portfolio actual cuyos
datos se están usando para generar un informe. Al usar estas variables donde corresponda,
podrá inicializarlas posteriormente en el interior del constructor PortfolioReport, como se
muestra en el ejemplo siguiente.

C#
Copiar
string path = "c:\\example\\";
string templateName = "PortfolioReport.xlsx";

WorkbookPart wbPart = null;


SpreadsheetDocument document = null;
Portfolio portfolio = null;

public PortfolioReport(string client)


{
string newFileName = path + client + ".xlsx";
CopyFile(path + templateName, newFileName);
document = SpreadsheetDocument.Open(newFileName, true);
wbPart = document.WorkbookPart;
portfolio = new Portfolio(client);
}

En este segmento de código, se puede ver lo fácil que es abrir un documento y extraer una
parte con Open XML SDK 2.0. En el constructor PortfolioReport, el archivo de libro se
abre con el método Open de la clase SpreadsheetDocument. SpreadsheetDocument forma
parte del espacio de nombres DocumentFormat.OpenXml.Packaging.
SpreadsheetDocument proporciona el acceso adecuado a la parte del libro del paquete del
documento por medio de una propiedad denominada WorkbookPart. Hasta esta fase del
proceso, el generador de informes ha realizado las acciones siguientes:

1. Crear una copia del archivo PortfolioReport.xlsx


2. Asignar el nombre del cliente a la copia
3. Abrir el informe del cliente para su edición
4. Extraer la parte de libro

Modificar los valores de las celdas de la hoja de cálculo con Open XML SDK

La tarea principal que debe resolverse a fin de completar el generador de informes es


determinar cómo se van a modificar los valores de un libro de Excel con Open XML SDK
2.0. Cuando se usa el modelo de objeto de Excel con Microsoft Visual Basic en
aplicaciones (VBA) o .NET, cambiar el valor de la celda es sencillo. Para cambiar el valor
de una celda (que es un objeto Range de un modelo de objeto de Excel), debe modificar el
valor de la propiedad Value. Por ejemplo, para cambiar el valor de la celda B4 en una hoja
de cálculo denominada Sales (Ventas) por el valor 250, utilizará la instrucción siguiente:

VBA
Copiar
ThisWorkbook.Worksheets("Sales").Range("B4").Value = 250
Open XML SDK 2.0 no funciona exactamente igual. Una gran diferencia es que al usar el
modelo de objeto de Excel puede manipular las celdas de las hojas de cálculo
independientemente de si contienen algún valor o no. Es decir, para el modelo de objeto,
todas las celdas de una hoja de cálculo existen. Cuando se trabaja con Open XML, los
objetos no existen. Esto ocurre de forma predeterminada. Si una celda no tiene un valor, no
existe, lo que es lógico desde la perspectiva de especificación de formatos de archivo. Para
mantener el tamaño de un archivo lo más pequeño posible, solo se guarda la información
importante. Vuelva a examinar, por ejemplo, la figura 4 y observe el primer nodo de fila
situado debajo de sheetData. La primera fila empieza en el 3, se saltan las filas 1 y 2. Esto
ocurre porque las celdas de las dos primeras filas están vacías. Observe, igualmente, que en
el primer nodo de fila (fila 3), la dirección de la primera celda es C3. Esto ocurre porque A3
y B3 están vacías.

Como no se puede presuponer que una celda exista en un documento Open XML, primero
debe comprobar si existe y, después, si no existe, debe agregarla al archivo. En el ejemplo
siguiente, se muestra un método denominado InsertCellInWorksheet que lleva a cabo esta
función, junto con los demás métodos del listado. Agregue estos métodos a la clase
PortfolioReport.

Nota
Microsoft tiene ejemplos de código para muchas tareas de Open XML SDK 2.0 comunes.
No solo eso, estos ejemplos están disponibles como ejemplos de código que pueden usarse
en Visual Studio 2010. Parte del código de este artículo se basa en estos ejemplos de
código. Puede descargar el código de ejemplo (en inglés) desde aquí.
C#
Copiar
// Given a Worksheet and an address (like "AZ254"), either return
a
// cell reference, or create the cell reference and return it.
private Cell InsertCellInWorksheet(Worksheet ws, string
addressName)
{
SheetData sheetData = ws.GetFirstChild<SheetData>();
Cell cell = null;

UInt32 rowNumber = GetRowIndex(addressName);


Row row = GetRow(sheetData, rowNumber);

// If the cell you need already exists, return it.


// If there is not a cell with the specified column name,
insert one.
Cell refCell = row.Elements<Cell>().
Where(c => c.CellReference.Value ==
addressName).FirstOrDefault();
if (refCell != null)
{
cell = refCell;
}
else
{
cell = CreateCell(row, addressName);
}
return cell;
}

// Add a cell with the specified address to a row.


private Cell CreateCell(Row row, String address)
{
Cell cellResult;
Cell refCell = null;

// Cells must be in sequential order according to


CellReference.
// Determine where to insert the new cell.
foreach (Cell cell in row.Elements<Cell>())
{
if (string.Compare(cell.CellReference.Value, address,
true) > 0)
{
refCell = cell;
break;
}
}

cellResult = new Cell();


cellResult.CellReference = address;

row.InsertBefore(cellResult, refCell);
return cellResult;
}

// Return the row at the specified rowIndex located within


// the sheet data passed in via wsData. If the row does not
// exist, create it.
private Row GetRow(SheetData wsData, UInt32 rowIndex)
{
var row = wsData.Elements<Row>().
Where(r => r.RowIndex.Value == rowIndex).FirstOrDefault();
if (row == null)
{
row = new Row();
row.RowIndex = rowIndex;
wsData.Append(row);
}
return row;
}

// Given an Excel address such as E5 or AB128, GetRowIndex


// parses the address and returns the row index.
private UInt32 GetRowIndex(string address)
{
string rowPart;
UInt32 l;
UInt32 result = 0;

for (int i = 0; i < address.Length; i++)


{
if (UInt32.TryParse(address.Substring(i, 1), out l))
{
rowPart = address.Substring(i, address.Length - i);
if (UInt32.TryParse(rowPart, out l))
{
result = l;
break;
}
}
}
return result;
}

Otra diferencia entre usar el modelo de objeto de Excel y manipular un documento Open
XML es que cuando se usa el modelo de objeto de Excel, los tipos de datos del valor que
proporcione a la celda o al rango no son relevantes. En cambio, si modifica el valor de una
celda con Open XML, el proceso varía en función del tipo de datos del valor. Para los
valores numéricos, el proceso es en parte parecido a usar el modelo de objeto de Excel. Hay
una propiedad asociada al objeto de Cell en Open XML SDK 2.0 denominada CellValue.
Puede usar esta propiedad para asignar valores numéricos a una celda.

La operación de almacenar cadenas o texto en una celda funciona de modo diferente. En


lugar de almacenar directamente el texto en una celda, Excel lo almacena en una tabla de
cadenas compartidas. La tabla de cadenas compartidas es simplemente un listado de todas
las cadenas exclusivas del libro en el que cada cadena exclusiva está asociada con un
índice. Para asociar una celda con un índice, la celda contiene una referencia al índice de
cadenas en lugar de la propia cadena. Cuando se cambia el valor de la celda por una
cadena, primero se debe comprobar si la cadena se encuentra en la tabla de cadenas
compartidas. Si está, se busca el índice de cadenas compartidas y se almacena en dicha
celda. Si la cadena no está en la tabla de cadenas compartidas, debe agregarla, recuperar su
índice de cadenas y almacenar el índice de cadenas en la celda. En el ejemplo siguiente, se
muestra el método UpdateValue que se usa para cambiar los valores de una celda y
InsertSharedStringItempara actualizar la tabla de cadenas compartidas.

C#
Copiar
public bool UpdateValue(string sheetName, string addressName,
string value,
UInt32Value styleIndex, bool isString)
{
// Assume failure.
bool updated = false;

Sheet sheet = wbPart.Workbook.Descendants<Sheet>().Where(


(s) => s.Name == sheetName).FirstOrDefault();

if (sheet != null)
{
Worksheet ws =
((WorksheetPart)(wbPart.GetPartById(sheet.Id))).Worksheet;
Cell cell = InsertCellInWorksheet(ws, addressName);
if (isString)
{
// Either retrieve the index of an existing string,
// or insert the string into the shared string table
// and get the index of the new item.
int stringIndex = InsertSharedStringItem(wbPart,
value);

cell.CellValue = new
CellValue(stringIndex.ToString());
cell.DataType = new
EnumValue<CellValues>(CellValues.SharedString);
}
else
{
cell.CellValue = new CellValue(value);
cell.DataType = new
EnumValue<CellValues>(CellValues.Number);
}

if (styleIndex > 0)
cell.StyleIndex = styleIndex;

// Save the worksheet.


ws.Save();
updated = true;
}

return updated;
}

// Given the main workbook part, and a text value, insert the
text into
// the shared string table. Create the table if necessary. If the
value
// already exists, return its index. If it doesn't exist, insert
it and
// return its new index.
private int InsertSharedStringItem(WorkbookPart wbPart, string
value)
{
int index = 0;
bool found = false;
var stringTablePart = wbPart

.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();

// If the shared string table is missing, something's wrong.


// Just return the index that you found in the cell.
// Otherwise, look up the correct text in the table.
if (stringTablePart == null)
{
// Create it.
stringTablePart =
wbPart.AddNewPart<SharedStringTablePart>();
}
var stringTable = stringTablePart.SharedStringTable;
if (stringTable == null)
{
stringTable = new SharedStringTable();
}

// Iterate through all the items in the SharedStringTable.


// If the text already exists, return its index.
foreach (SharedStringItem item in
stringTable.Elements<SharedStringItem>())
{
if (item.InnerText == value)
{
found = true;
break;
}
index += 1;
}

if (!found)
{
stringTable.AppendChild(new SharedStringItem(new
Text(value)));
stringTable.Save();
}

return index;
}

Un punto interesante del ejemplo de código anterior es el formato de las celdas. Como ya
hemos mencionado en este artículo, el formato de las celdas no se almacena en los nodos de
celda, sino que la celda almacena un índice de estilos que apunta a un estilo que está
definido en otra parte (styles.xml). Si se usa el patrón de plantilla mostrado en este
documento y el modelo de objeto de Excel mediante VBA o .NET, normalmente, se aplica
el formato que se desea a un rango de una o más celdas. A medida que se agregan mediante
programación datos al libro, se aplica fielmente el formato que se ha aplicado en el rango.

Puesto que los archivos Open XML solo contienen información relacionada con las celdas
que contienen datos, cuando se agregue una celda nueva al archivo, si la celda necesita
formato, se deberá actualizar en el índice de estilos. En consecuencia, el método
UpdateValue acepta un parámetro styleIndex que indica qué índice de estilos se aplica a la
celda. Si pasa un valor cero, no se define ningún índice de estilos y la celda usa el formato
predeterminado de Excel.

Un método sencillo para determinar el índice de estilos apropiado para cada celda es dar el
formato que desee al archivo de plantilla del libro y después abrir las partes del libro
correspondientes en modo XML (como se muestra en la figura 4) y buscar el índice de
estilo de las celdas a las que ha dado formato.

Con los métodos del listado de códigos anterior implementados, para generar el informe
ahora basta con obtener los datos de la cartera y llamar repetidamente a UpdateValue para
crear el informe. Si agrega el código necesario para hacerlo, todo funcionará bien salvo una
cuestión: las celdas que contengan una fórmula que haga referencia a una celda cuyo valor
se haya cambiado manipulando Open XML no mostrarán el resultado correcto. Esto sucede
porque Excel almacena en la caché el resultado de la fórmula de la celda. Como Excel cree
que tiene el valor correcto en la caché, no vuelve a calcular la celda. Aunque tenga la
función de cálculo automático activada o presione F9 para realizar un cálculo manual,
Excel no vuelve a calcular la celda.

Para solucionar este problema, debe eliminar el valor almacenado en la caché de estas
celdas de modo que Excel vuelva a realizar el cálculo cuando el archivo se abra en Excel.
Para proporcionar esta función, agregue el método RemoveCellValue mostrado en el
ejemplo siguiente a la clase PortfolioReport.

C#
Copiar
// This method is used to force a recalculation of cells
containing formulas. The
// CellValue has a cached value of the evaluated formula. This
// prevents Excel from recalculating the cell even if
// calculation is set to automatic.
private bool RemoveCellValue(string sheetName, string
addressName)
{
bool returnValue = false;

Sheet sheet = wbPart.Workbook.Descendants<Sheet>().


Where(s => s.Name == sheetName).FirstOrDefault();
if (sheet != null)
{
Worksheet ws =
((WorksheetPart)(wbPart.GetPartById(sheet.Id))).Worksheet;
Cell cell = InsertCellInWorksheet(ws, addressName);

// If there is a cell value, remove it to force a


recalculation
// on this cell.
if (cell.CellValue != null)
{
cell.CellValue.Remove();
}

// Save the worksheet.


ws.Save();
returnValue = true;
}

return returnValue;
}

Para completar la clase PortfolioReport, agregue el método CreateReport mostrado en el


ejemplo siguiente a la clase PortfolioReport. Este método usa el método UpdateValue de
CreateReport para colocar la información de la cartera en las celdas que desee. Después de
actualizar todas las celdas necesarias, llama a RemoveCellValue en cada celda que debe
volverse a calcular. Por último, CreateReport llama al método Close en
SpreadsheetDocument para guardar todos los cambios y cerrar el archivo.

C#
Copiar
// Create a new Portfolio report
public void CreateReport()
{
string wsName = "Portfolio Summary";

UpdateValue(wsName, "J2", "Prepared for " + portfolio.Name,


0, true);
UpdateValue(wsName, "J3", "Account # " +
portfolio.AccountNumber.ToString(), 0, true);
UpdateValue(wsName, "D9",
portfolio.BeginningValueQTR.ToString(), 0, false);
UpdateValue(wsName, "E9",
portfolio.BeginningValueYTD.ToString(), 0, false);
UpdateValue(wsName, "D11",
portfolio.ContributionsQTR.ToString(), 0, false);
UpdateValue(wsName, "E11",
portfolio.ContributionsYTD.ToString(), 0, false);
UpdateValue(wsName, "D12",
portfolio.WithdrawalsQTR.ToString(), 0, false);
UpdateValue(wsName, "E12",
portfolio.WithdrawalsYTD.ToString(), 0, false);
UpdateValue(wsName, "D13",
portfolio.DistributionsQTR.ToString(), 0, false);
UpdateValue(wsName, "E13",
portfolio.DistributionsYTD.ToString(), 0, false);
UpdateValue(wsName, "D14", portfolio.FeesQTR.ToString(), 0,
false);
UpdateValue(wsName, "E14", portfolio.FeesYTD.ToString(), 0,
false);
UpdateValue(wsName, "D15", portfolio.GainLossQTR.ToString(),
0, false);
UpdateValue(wsName, "E15", portfolio.GainLossYTD.ToString(),
0, false);

int row = 7;
wsName = "Portfolio Holdings";

UpdateValue(wsName, "J2", "Prepared for " + portfolio.Name,


0, true);
UpdateValue(wsName, "J3", "Account # " +
portfolio.AccountNumber.ToString(), 0, true);
foreach (PortfolioItem item in portfolio.Holdings)
{
UpdateValue(wsName, "B" + row.ToString(),
item.Description, 3, true);
UpdateValue(wsName, "D" + row.ToString(),
item.CurrentPrice.ToString(), 24, false);
UpdateValue(wsName, "E" + row.ToString(),
item.SharesHeld.ToString(), 27, false);
UpdateValue(wsName, "F" + row.ToString(),
item.MarketValue.ToString(), 24, false);
UpdateValue(wsName, "G" + row.ToString(),
item.Cost.ToString(), 24, false);
UpdateValue(wsName, "H" + row.ToString(),
item.High52Week.ToString(), 28, false);
UpdateValue(wsName, "I" + row.ToString(),
item.Low52Week.ToString(), 28, false);
UpdateValue(wsName, "J" + row.ToString(), item.Ticker,
11, true);
row++;
}

// Force re-calc when the workbook is opened


this.RemoveCellValue("Portfolio Summary", "D17");
this.RemoveCellValue("Portfolio Summary", "E17");

// All done! Close and save the document.


document.Close();
}

Uso de la clase PortfolioReport

El paso final (presuponiendo que haya copiado el origen de la clase Portfolio) es agregar
código al método Main de la clase Program. Modifique el método Main de modo que
contenga el código mostrado en el ejemplo siguiente. Observe que el origen de la clase
Portfolio incluye datos de ejemplo para dos clientes: Steve y Kelly.

C#
Copiar
static void Main(string[] args)
{
PortfolioReport report = new PortfolioReport("Steve");
report.CreateReport();
report = new PortfolioReport("Kelly");
report.CreateReport();
Console.WriteLine("Reports created!");
Console.WriteLine("Press ENTER to quit.");
Console.ReadLine();
}

Uno de los efectos que se aprecia cuando se ejecuta este proceso es lo rápido que se
generan los informes, lo que es idóneo para aquellos casos en los que se hace un uso
intensivo del servidor. El rendimiento en comparación con código parecido que usa el
modelo de objeto de Excel para alcanzar el mismo resultado ni siquiera se acerca a este: el
método Open XML es muchísimo más rápido.

Conclusión

Comenzando con Microsoft Office 2007, las aplicaciones principales de Microsoft Office
centradas en documentos han cambiado el formato usual de archivo binario por el formato
de archivos Open XML. Los formatos de archivo Open XML son formatos de archivo
basados en estándares abiertos XML. El paso a los formatos de archivo Open XML abre
nuevas oportunidades de desarrollo para los desarrolladores. Pero, para poder aprovechar
estas oportunidades, se tiene que invertir mucho tiempo y esfuerzo para entender la
especificación Open XML y en la tediosa manipulación de XML sin formato.

Con Open XML SDK 2.0, no es necesario dedicar tanto tiempo al aprendizaje de la técnica
de desarrollo, porque encapsula muchos de los detalles de la especificación Open XML en
una biblioteca de clases fácil de usar para trabajar con documentos Open XML. Además de
reducir el tiempo de aprendizaje, con Open XML SDK 2.0, los desarrolladores podrán ser
más productivos al proporcionar funciones durante el diseño, como la compatibilidad con
IntelliSense y un desarrollo con seguridad de tipos.

En este artículo, se ha mostrado cómo usar Open XML SDK 2.0 para crear un generador de
informes de cartera. Este ejercicio ha mostrado un patrón de solución común y una
estrategia para las tareas orientadas a Excel comunes, como abrir libros, hacer referencia a
hojas de cálculo y actualizar el valor de una celda.

Recursos adicionales

Para obtener más información acerca de los temas tratados en este artículo, consulte los
siguientes recursos adicionales.

 Descargue Open XML SDK 2.0 (en inglés)


 OpenXML Developer (en inglés) (en inglés)
 Introducing the Office Open XML File Formats
 Centro para desarrolladores de Office XML (en inglés) (en inglés)

Acerca del autor

Steve Hansen es el fundador de Grid Logic, una consultoría con sede principal en
Minnesota especializada en soluciones para trabajadores de la información e inteligencia
empresarial. Steve es desarrollador, autor de muchos artículos y ponente en conferencias
técnicas, es un MVP de Microsoft por su trabajo con herramientas de Visual Studio para
Office. Programador y amante de la economía, Steve cuenta también con un MBA de la
Universidad de Minnesota en la especialización de finanzas.

También podría gustarte