Share via


Recuperar los valores de las celdas de un documento de hoja de cálculo

En este tema se muestra cómo usar las clases del SDK de Open XML para Office para recuperar mediante programación los valores de las celdas de un documento de hoja de cálculo. Contiene un ejemplo del método GetCellValue para ilustrar esta tarea.

Método GetCellValue

Puede usar el método GetCellValue para recuperar el valor de una celda en un libro. El método requiere los tres parámetros siguientes:

  • Cadena que contiene el nombre del documento que se va a examinar.

  • Cadena que contiene el nombre de la hoja que se va a examinar.

  • Cadena que contiene la dirección de la celda (como A1, B12) desde la que se va a recuperar un valor.

El método devuelve el valor de la celda especificada, si se encontrara. El siguiente ejemplo de código muestra la firma del método.

static string GetCellValue(string fileName, string sheetName, string addressName)

Funcionamiento del código

El código se inicia creando una variable para retener el valor devuelto y lo inicializa a nulo.

string? value = null;

Acceder a la celda

A continuación, el código abre el documento mediante el método Open , lo que indica que el documento debe estar abierto para el acceso de solo lectura (el parámetro false final). A continuación, el código recupera una referencia a la parte del libro mediante la propiedad WorkbookPart del documento.

// Open the spreadsheet document for read-only access.
using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false))
{
    // Retrieve a reference to the workbook part.
    WorkbookPart? wbPart = document.WorkbookPart;

Para buscar la celda solicitada, el código debe recuperar primero la hoja de acuerdo con su nombre. El código debe buscar en todos los descendientes de tipo hoja del elemento de libro de elementos del libro y examinar la propiedad Name de cada hoja que encuentre. Tenga en cuenta que esta búsqueda busca en las relaciones del libro y en realidad no encuentra una parte de la hoja. Busca una referencia a una hoja, que contiene información como el nombre y el identificador de la hoja. El modo más sencillo de hacerlo es utilizar una consulta LINQ, tal como se muestra en el siguiente ejemplo de código.

// Find the sheet with the supplied name, and then use that 
// Sheet object to retrieve a reference to the first worksheet.
Sheet? theSheet = wbPart?.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).FirstOrDefault();

// Throw an exception if there is no sheet.
if (theSheet is null || theSheet.Id is null)
{
    throw new ArgumentException("sheetName");
}

Tenga en cuenta que el método FirstOrDefault devuelve la primera referencia coincidente (una hoja, en este caso) o una referencia nula si no se encontró ninguna coincidencia. El código comprueba la referencia nula y produce una excepción si ha pasado un nombre de hoja no válido. Ahora que tiene información sobre la hoja, el código debe recuperar una referencia a la parte de hoja de cálculo correspondiente. La información de hoja que ya ha recuperado proporciona una propiedad Id y, dado que la propiedad Id , el código puede recuperar una referencia al elemento WorksheetPart correspondiente llamando al método GetPartById de la parte del libro.

// Retrieve a reference to the worksheet part.
WorksheetPart wsPart = (WorksheetPart)wbPart!.GetPartById(theSheet.Id!);

Al igual que al buscar la hoja con nombre, al buscar la celda con nombre, el código usa el método Descendants , buscando la primera coincidencia en la que la propiedad CellReference es igual al parámetro addressName especificado. Tras esta llamada de método, la variable llamada theCell contendrá una referencia a la celda o bien una referencia nula.

// Use its Worksheet property to get a reference to the cell 
// whose address matches the address you supplied.
Cell? theCell = wsPart.Worksheet?.Descendants<Cell>()?.Where(c => c.CellReference == addressName).FirstOrDefault();

Recuperación del valor

Llegados a este punto, la variable llamada theCell contiene una referencia nula o una referencia a la celda que ha solicitado. Si examina el contenido de Open XML (es decir, theCell.OuterXml) en busca de la celda, encontrará XML como el siguiente.

    <x:c r="A1">
        <x:v>12.345000000000001</x:v>
    </x:c>

La propiedad InnerText contiene el contenido de la celda, por lo que el siguiente bloque de código recupera este valor.

// If the cell does not exist, return an empty string.
if (theCell is null || theCell.InnerText.Length < 0)
{
    return string.Empty;
}
value = theCell.InnerText;

El método de ejemplo debe interpretar el valor. De este modo, el código gestiona valores numéricos, de fecha, de cadena y booleanos. Puede ampliar el ejemplo como considere necesario. El tipo Cell proporciona una propiedad DataType que indica el tipo de los datos dentro de la celda. El valor de la propiedad DataType es nulo para tipos numéricos y de fecha. Contiene el valor CellValues.SharedString para cadenas y CellValues.Boolean para valores booleanos. Si la propiedad DataType es nula, el código devuelve el valor de la celda (es un valor numérico). De lo contrario, el código continúa mediante bifurcación basándose en el tipo de datos.

// If the cell represents an integer number, you are done. 
// For dates, this code returns the serialized value that 
// represents the date. The code handles strings and 
// Booleans individually. For shared strings, the code 
// looks up the corresponding value in the shared string 
// table. For Booleans, the code converts the value into 
// the words TRUE or FALSE.
if (theCell.DataType is not null)
{
    if (theCell.DataType.Value == CellValues.SharedString)
    {

Si la propiedad DataType contiene CellValues.SharedString, el código debe recuperar una referencia al elemento SharedStringTablePart único.

// For shared strings, look up the value in the
// shared strings table.
var stringTable = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();

A continuación, si existe la tabla (y si no, el libro está dañado y el código de ejemplo devuelve el índice en la tabla de cadenas en lugar de la propia cadena) el código devuelve la propiedad InnerText del elemento si la encuentra en un índice determinado (primero convirtiendo la propiedad del valor a entero).

// If the shared string table is missing, something 
// is wrong. Return the index that is in
// the cell. Otherwise, look up the correct text in 
// the table.
if (stringTable is not null)
{
    value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
}

Si la propiedad DataType contiene CellValues.Boolean, el código convierte el 0 o 1 que encuentra en el valor de la celda en la cadena de texto apropiada.

switch (value)
{
    case "0":
        value = "FALSE";
        break;
    default:
        value = "TRUE";

Por último, el procedimiento devuelve la variable value, que contiene la información solicitada.

Código de ejemplo

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

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

Console.WriteLine(GetCellValue(args[0], args[1], args[2]));
// Retrieve the value of a cell, given a file name, sheet name, 
// and address name.
static string GetCellValue(string fileName, string sheetName, string addressName)
{
    string? value = null;
    // Open the spreadsheet document for read-only access.
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false))
    {
        // Retrieve a reference to the workbook part.
        WorkbookPart? wbPart = document.WorkbookPart;
        // Find the sheet with the supplied name, and then use that 
        // Sheet object to retrieve a reference to the first worksheet.
        Sheet? theSheet = wbPart?.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).FirstOrDefault();

        // Throw an exception if there is no sheet.
        if (theSheet is null || theSheet.Id is null)
        {
            throw new ArgumentException("sheetName");
        }
        // Retrieve a reference to the worksheet part.
        WorksheetPart wsPart = (WorksheetPart)wbPart!.GetPartById(theSheet.Id!);
        // Use its Worksheet property to get a reference to the cell 
        // whose address matches the address you supplied.
        Cell? theCell = wsPart.Worksheet?.Descendants<Cell>()?.Where(c => c.CellReference == addressName).FirstOrDefault();
        // If the cell does not exist, return an empty string.
        if (theCell is null || theCell.InnerText.Length < 0)
        {
            return string.Empty;
        }
        value = theCell.InnerText;
        // If the cell represents an integer number, you are done. 
        // For dates, this code returns the serialized value that 
        // represents the date. The code handles strings and 
        // Booleans individually. For shared strings, the code 
        // looks up the corresponding value in the shared string 
        // table. For Booleans, the code converts the value into 
        // the words TRUE or FALSE.
        if (theCell.DataType is not null)
        {
            if (theCell.DataType.Value == CellValues.SharedString)
            {
                // For shared strings, look up the value in the
                // shared strings table.
                var stringTable = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
                // If the shared string table is missing, something 
                // is wrong. Return the index that is in
                // the cell. Otherwise, look up the correct text in 
                // the table.
                if (stringTable is not null)
                {
                    value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
                }
            }
            else if (theCell.DataType.Value == CellValues.Boolean)
            {
                switch (value)
                {
                    case "0":
                        value = "FALSE";
                        break;
                    default:
                        value = "TRUE";
                        break;
                }
            }
        }
    }

    return value;
}