Procedimiento para insertar texto en una celda de un documento de hoja de cálculo (SDK de Open XML)

Office 2013 y posterior

Esta documentación es preliminar y está sujeta a modificaciones.

Última modificación:miércoles, 17 de febrero de 2016

Hace referencia a:Office 2013 | Open XML

En este tema se muestra cómo usar las clases de SDK de Open XML 2.5 para Office para insertar mediante programación texto en una celda de una hoja de cálculo nueva de un documento de hoja de cálculo.

Se requieren las siguientes directivas de ensamblado para compilar el código de este tema:

using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

Imports System.Linq
Imports DocumentFormat.OpenXml
Imports DocumentFormat.OpenXml.Packaging
Imports DocumentFormat.OpenXml.Spreadsheet

En Open XML SDK, la clase SpreadsheetDocument representa un paquete de documentos de Excel. Para abrir y trabajar con un documento de Excel, cree una instancia de la clase SpreadsheetDocument desde el documento. Después de crear la instancia desde el documento, puede obtener acceso a la parte de libro principal que contiene las hojas de cálculo. En el paquete, el texto del documento se representa como XML mediante el marcado SpreadsheetML.

Para crear la instancia de clase desde un documento, debe llamar a uno de los métodos de sobrecarga Open(). Se proporcionan varios métodos, cada uno con una firma distinta. El código muestra de este tema usa el método Open(String, Boolean) con una firma que necesita dos parámetros. El primero toma una cadena de ruta de acceso completa que representa el documento que desea abrir. El segundo es true o false y representa si desea que el archivo se abra para edición o no. Si el parámetro es false, los cambios que realice en el documento no se guardarán.

El código que llama al método Open se muestra en la siguiente instrucción using.

// Open the document for editing.
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docName, true)) 
{
    // Insert other code here.
}

La instrucción using proporciona una alternativa recomendada a la típica secuencia .Open, .Save, .Close. Garantiza que se llamará automáticamente al método Dispose (un método interno que Open XML SDK usa para limpiar recursos) cuando se llegue a la llave de cierre. El bloque que sigue a la instrucción using establece un ámbito para el objeto que se crea o se nombra en la instrucción using, en este caso spreadSheet.

La estructura básica de un documento SpreadsheetML consta de los elementos Sheets y Sheet, que hacen referencia a las hojas de cálculo del libro. Se crea un archivo XML independiente para cada Worksheet. Por ejemplo, el SpreadsheetML de un Workbook que tiene dos hojas de cálculo con los nombres MySheet1 y MySheet2 se encuentra en el archivo Workbook.xml y se muestra en el siguiente ejemplo de código.

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
<workbook xmlns=http://schemas.openxmlformats.org/spreadsheetml/2006/main xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
    <sheets>
        <sheet name="MySheet1" sheetId="1" r:id="rId1" /> 
        <sheet name="MySheet2" sheetId="2" r:id="rId2" /> 
    </sheets>
</workbook>

Los archivos XML de hojas de cálculo contienen uno o más elementos a nivel de bloque, como SheetData. sheetData representa la tabla de celdas y contiene uno o más elementos Row. Una row contiene uno o más elementos Cell. Cada celda contiene un elemento CellValue que representa el valor de la celda. Por ejemplo, el documento SpreadsheetML para la primera hoja de cálculo de un libro, que solo tiene el valor 100 en la celda A1, está ubicado en el archivo Sheet1.xml y se muestra en el siguiente ejemplo de código.

<?xml version="1.0" encoding="UTF-8" ?> 
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <sheetData>
        <row r="1">
            <c r="A1">
                <v>100</v> 
            </c>
        </row>
    </sheetData>
</worksheet>

Con SDK de Open XML 2.5 puede crear contenido y estructuras de documentos con clases fuertemente tipadas que corresponden a los elementos SpreadsheetML. Puede encontrar estas clases en el espacio de nombres DocumentFormat.OpenXML.Spreadsheet. En la tabla siguiente se enumeran los nombres de las clases que corresponden a los elementos workbook, sheets, sheet, worksheet y sheetData.

Elemento de SpreadsheetML

Clase de SDK de Open XML 2.5

Descripción

workbook

DocumentFormat.OpenXml.Spreadsheet.Workbook

El elemento raíz de la parte de documento principal.

sheets

DocumentFormat.OpenXml.Spreadsheet.Sheets

El contenedor de las estructuras del nivel de bloque, como sheet, fileVersion y otras que se detallan en la especificación ISO/IEC 29500.

sheet

DocumentFormat.OpenXml.Spreadsheet.Sheet

Una hoja que apunta a un archivo de definición de hoja.

worksheet

DocumentFormat.OpenXml.Spreadsheet.Worksheet

Un archivo de definición de hoja que contiene los datos de la hoja.

sheetData

DocumentFormat.OpenXml.Spreadsheet.SheetData

La tabla de celdas agrupadas por filas.

row

DocumentFormat.OpenXml.Spreadsheet.Row

Una fila en una tabla de celdas.

c

DocumentFormat.OpenXml.Spreadsheet.Cell

Una celda en una fila.

v

DocumentFormat.OpenXml.Spreadsheet.CellValue

El valor de una celda.

Después de abrir el documento SpreadsheetDocument para su edición, el código inserta un objeto Worksheet vacío en un paquete de documentos SpreadsheetDocument. A continuación, inserta un nuevo objeto Cell en la nueva hoja de cálculo e inserta el texto especificado en esa celda.

// Given a document name and text, 
// inserts a new worksheet and writes the text to cell "A1" of the new worksheet.
public static void InsertText(string docName, string text)
{
    // Open the document for editing.
    using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docName, true))
    {
        // Get the SharedStringTablePart. If it does not exist, create a new one.
        SharedStringTablePart shareStringPart;
        if (spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
        {
            shareStringPart = spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
        }
        else
        {
            shareStringPart = spreadSheet.WorkbookPart.AddNewPart<SharedStringTablePart>();
        }

        // Insert the text into the SharedStringTablePart.
        int index = InsertSharedStringItem(text, shareStringPart);

        // Insert a new worksheet.
        WorksheetPart worksheetPart = InsertWorksheet(spreadSheet.WorkbookPart);

        // Insert cell A1 into the new worksheet.
        Cell cell = InsertCellInWorksheet("A", 1, worksheetPart);

        // Set the value of cell A1.
        cell.CellValue = new CellValue(index.ToString());
        cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);

        // Save the new worksheet.
        worksheetPart.Worksheet.Save();
    }
}

El código pasa un parámetro que representa el texto que se desea insertar en la celda y un parámetro que representa el objeto SharedStringTablePart de la hoja de cálculo. Si el objeto ShareStringTablePart no contiene un objeto SharedStringTable, el código crea uno. Si el texto ya existe en el objeto ShareStringTable, el código devuelve el índice del objeto SharedStringItem que representa el texto. De lo contrario, crea un nuevo objeto SharedStringItem que representa el texto.

El siguiente código comprueba si el texto especificado existe en el objeto SharedStringTablePart; si no existe, lo agrega.

// Given text and a SharedStringTablePart, creates a SharedStringItem with the specified text 
// and inserts it into the SharedStringTablePart. If the item already exists, returns its index.
private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
{
    // If the part does not contain a SharedStringTable, create one.
    if (shareStringPart.SharedStringTable == null)
    {
        shareStringPart.SharedStringTable = new SharedStringTable();
    }

    int i = 0;

    // Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
    foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>())
    {
        if (item.InnerText == text)
        {
            return i;
        }

        i++;
    }

    // The text does not exist in the part. Create the SharedStringItem and return its index.
    shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
    shareStringPart.SharedStringTable.Save();

    return i;
}

El código agrega un nuevo objeto WorksheetPart al objeto WorkbookPart mediante el método AddNewPart. A continuación, agrega un nuevo objeto Worksheet al objeto WorksheetPart y obtiene un identificador único para la nueva hoja de cálculo mediante la selección del objeto SheetId máximo, que se usa dentro del documento de hoja de cálculo, y la adición de uno para crear el nuevo identificador de hoja. Asigna un nombre a la hoja de cálculo concatenando la palabra "Sheet" (Hoja) con el identificador de la hoja. Luego, anexa el nuevo objeto Sheet a la colección Sheets.

El siguiente código inserta un nuevo objeto Worksheet mediante la adición de un nuevo objeto WorksheetPart al objeto WorkbookPart.

// Given a WorkbookPart, inserts a new worksheet.
private static WorksheetPart InsertWorksheet(WorkbookPart workbookPart)
{
    // Add a new worksheet part to the workbook.
    WorksheetPart newWorksheetPart = workbookPart.AddNewPart<WorksheetPart>();
    newWorksheetPart.Worksheet = new Worksheet(new SheetData());
    newWorksheetPart.Worksheet.Save();

    Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>();
    string relationshipId = workbookPart.GetIdOfPart(newWorksheetPart);

    // Get a unique ID for the new sheet.
    uint sheetId = 1;
    if (sheets.Elements<Sheet>().Count() > 0)
    {
        sheetId = sheets.Elements<Sheet>().Select(s => s.SheetId.Value).Max() + 1;
    }

    string sheetName = "Sheet" + sheetId;

    // Append the new worksheet and associate it with the workbook.
    Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetName };
    sheets.Append(sheet);
    workbookPart.Workbook.Save();

    return newWorksheetPart;
}

Para insertar una celda en una hoja de cálculo, el código determina dónde se insertará la nueva celda de la columna mediante una iteración a través de los elementos de la fila para buscar la celda inmediatamente posterior a la fila especificada, en orden secuencial. Guarda esta fila en la variable refCell. A continuación, inserta la nueva celda delante de la celda a la que hace referencia refCell mediante el método InsertBefore.

En el siguiente código, inserte un nuevo objeto Cell en un objeto Worksheet.

// Given a column name, a row index, and a WorksheetPart, inserts a cell into the worksheet. 
// If the cell already exists, returns it. 
private static Cell InsertCellInWorksheet(string columnName, uint rowIndex, WorksheetPart worksheetPart)
{
    Worksheet worksheet = worksheetPart.Worksheet;
    SheetData sheetData = worksheet.GetFirstChild<SheetData>();
    string cellReference = columnName + rowIndex;

    // If the worksheet does not contain a row with the specified row index, insert one.
    Row row;
    if (sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
    {
        row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
    }
    else
    {
        row = new Row() { RowIndex = rowIndex };
        sheetData.Append(row);
    }

    // If there is not a cell with the specified column name, insert one.  
    if (row.Elements<Cell>().Where(c => c.CellReference.Value == columnName + rowIndex).Count() > 0)
    {
        return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First();
    }
    else
    {
        // Cells must be in sequential order according to CellReference. Determine where to insert the new cell.
        Cell refCell = null;
        foreach (Cell cell in row.Elements<Cell>())
        {
            if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
            {
                refCell = cell;
                break;
            }
        }

        Cell newCell = new Cell() { CellReference = cellReference };
        row.InsertBefore(newCell, refCell);

        worksheet.Save();
        return newCell;
    }
}

El ejemplo de código siguiente se usa para insertar una hoja de cálculo nueva y escribir el texto en la celda "A1" de la hoja de cálculo nueva para un documento de hoja de cálculo específico denominado "Sheet8.xlsx". Para llamar al método InsertText, puede usar el siguiente código como un ejemplo.

InsertText(@"C:\Users\Public\Documents\Sheet8.xlsx", "Inserted Text");

A continuación se incluye el código de ejemplo completo en C# y Visual Basic.

// Given a document name and text, 
 // inserts a new work sheet and writes the text to cell "A1" of the new worksheet.

 public static void InsertText(string docName, string text)
{
    // Open the document for editing.
    using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docName, true))
    {
        // Get the SharedStringTablePart. If it does not exist, create a new one.
        SharedStringTablePart shareStringPart;
        if (spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
        {
            shareStringPart = spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
        }
        else
        {
            shareStringPart = spreadSheet.WorkbookPart.AddNewPart<SharedStringTablePart>();
        }

        // Insert the text into the SharedStringTablePart.
        int index = InsertSharedStringItem(text, shareStringPart);

        // Insert a new worksheet.
        WorksheetPart worksheetPart = InsertWorksheet(spreadSheet.WorkbookPart);

        // Insert cell A1 into the new worksheet.
        Cell cell = InsertCellInWorksheet("A", 1, worksheetPart);

        // Set the value of cell A1.
        cell.CellValue = new CellValue(index.ToString());
        cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);

        // Save the new worksheet.
        worksheetPart.Worksheet.Save();
    }
}

        // Given text and a SharedStringTablePart, creates a SharedStringItem with the specified text 
        // and inserts it into the SharedStringTablePart. If the item already exists, returns its index.
        private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
        {
            // If the part does not contain a SharedStringTable, create one.
            if (shareStringPart.SharedStringTable == null)
            {
                shareStringPart.SharedStringTable = new SharedStringTable();
            }

            int i = 0;

            // Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
            foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>())
            {
                if (item.InnerText == text)
                {
                    return i;
                }

                i++;
            }

            // The text does not exist in the part. Create the SharedStringItem and return its index.
            shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
            shareStringPart.SharedStringTable.Save();

            return i;
        }

        // Given a WorkbookPart, inserts a new worksheet.
        private static WorksheetPart InsertWorksheet(WorkbookPart workbookPart)
        {
            // Add a new worksheet part to the workbook.
            WorksheetPart newWorksheetPart = workbookPart.AddNewPart<WorksheetPart>();
            newWorksheetPart.Worksheet = new Worksheet(new SheetData());
            newWorksheetPart.Worksheet.Save();

            Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>();
            string relationshipId = workbookPart.GetIdOfPart(newWorksheetPart);

            // Get a unique ID for the new sheet.
            uint sheetId = 1;
            if (sheets.Elements<Sheet>().Count() > 0)
            {
                sheetId = sheets.Elements<Sheet>().Select(s => s.SheetId.Value).Max() + 1;
            }

            string sheetName = "Sheet" + sheetId;

            // Append the new worksheet and associate it with the workbook.
            Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetName };
            sheets.Append(sheet);
            workbookPart.Workbook.Save();

            return newWorksheetPart;
        }

        // Given a column name, a row index, and a WorksheetPart, inserts a cell into the worksheet. 
        // If the cell already exists, returns it. 
        private static Cell InsertCellInWorksheet(string columnName, uint rowIndex, WorksheetPart worksheetPart)
        {
            Worksheet worksheet = worksheetPart.Worksheet;
            SheetData sheetData = worksheet.GetFirstChild<SheetData>();
            string cellReference = columnName + rowIndex;

            // If the worksheet does not contain a row with the specified row index, insert one.
            Row row;
            if (sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
            {
                row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
            }
            else
            {
                row = new Row() { RowIndex = rowIndex };
                sheetData.Append(row);
            }

            // If there is not a cell with the specified column name, insert one.  
            if (row.Elements<Cell>().Where(c => c.CellReference.Value == columnName + rowIndex).Count() > 0)
            {
                return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First();
            }
            else
            {
                // Cells must be in sequential order according to CellReference. Determine where to insert the new cell.
                Cell refCell = null;
                foreach (Cell cell in row.Elements<Cell>())
                {
                    if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
                    {
                        refCell = cell;
                        break;
                    }
                }

                Cell newCell = new Cell() { CellReference = cellReference };
                row.InsertBefore(newCell, refCell);

                worksheet.Save();
                return newCell;
            }
        }


Mostrar: