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 método de ejemplo GetCellValue
para ilustrar esta tarea.
Método GetCellValue
Puede usar el GetCellValue
método para recuperar el valor de una celda de 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 Open método , lo que indica que el documento debe estar abierto para el acceso de solo lectura (el parámetro final false
). A continuación, el código recupera una referencia a la parte del libro mediante la WorkbookPart propiedad 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 del libro y examinar la Name propiedad 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 , Sheetque contiene información como el nombre y Id 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 FirstOrDefault método 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 Id propiedad y, dado que la propiedad Id , el código puede recuperar una referencia al correspondiente WorksheetPart llamando al método de elemento GetPartById 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 Descendants método , buscando la primera coincidencia en la que la CellReference propiedad es igual a la especificada.
addressName
parámetro. 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
En este punto, la variable denominada theCell
contiene una referencia nula o una referencia a la celda que solicitó. Si examina el contenido de Open XML (es decir, theCell.OuterXml
) de la celda, encontrará XML como el siguiente.
<x:c r="A1">
<x:v>12.345000000000001</x:v>
</x:c>
La InnerText propiedad 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 Cell tipo proporciona una DataType propiedad que indica el tipo de los datos dentro de la celda. El valor de la DataType
propiedad es null para los tipos numéricos y de fecha. Contiene el valor CellValues.SharedString
de las cadenas y CellValues.Boolean
de los valores booleanos. Si la DataType
propiedad es null, 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 DataType
propiedad contiene CellValues.SharedString
, el código debe recuperar una referencia al único SharedStringTablePart.
// For shared strings, look up the value in the
// shared strings table.
var stringTable = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
A continuación, si la tabla de cadenas existe (y si no es así, 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 InnerText
propiedad del elemento que encuentra en el índice especificado (convirtiendo primero la propiedad value en un 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 DataType
propiedad contiene CellValues.Boolean
, el código convierte el 0 o 1 que encuentra en el valor de celda en la cadena de texto adecuada.
switch (value)
{
case "0":
value = "FALSE";
break;
default:
value = "TRUE";
break;
}
Por último, el procedimiento devuelve la variable value
, que contiene la información solicitada.
Código de ejemplo
A continuación se muestra el ejemplo de código completo GetCellValue
en C# y Visual Basic.
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;
}