Recuperar os valores das células em um documento de planilha

Este tópico mostra como usar as classes no Open XML SDK for Office para recuperar programaticamente os valores das células em um documento de planilha. Ele contém um método de exemplo GetCellValue para ilustrar essa tarefa.

Método GetCellValue

Você pode usar o GetCellValue método para recuperar o valor de uma célula em uma pasta de trabalho. O método requer os três parâmetros a seguir:

  • Uma cadeia de caracteres que contém o nome do documento a ser examinado.

  • Uma cadeia de caracteres que contém o nome da planilha a ser examinada.

  • Uma cadeia de caracteres que contém o endereço de célula (como A1, B12) do qual recuperar um valor.

O método retorna o valor da célula especificada, se puder ser encontrada. O exemplo de código a seguir mostra a assinatura do método.

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

Como o código funciona

O código começa criando uma variável para conter o valor retornado e inicializa-o como nulo.

string? value = null;

Acessando a célula

Em seguida, o código abre o documento usando o Open método, indicando que o documento deve ser aberto para acesso somente leitura (o parâmetro final false ). Em seguida, o código recupera uma referência à parte da pasta de trabalho usando a WorkbookPart propriedade do 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 localizar a célula solicitada, o código deve primeiro recuperar uma referência à planilha, dado seu nome. O código deve pesquisar todos os descendentes do tipo folha do elemento de pasta de trabalho da parte da pasta de trabalho e examinar a Name propriedade de cada folha que encontrar. Esteja ciente de que essa pesquisa examina as relações da pasta de trabalho e não encontra uma parte da planilha. Ele encontra uma referência a um Sheet, que contém informações como o nome e Id a da planilha. A maneira mais simples de fazer isso é usar uma consulta LINQ, conforme mostrado no exemplo de código a seguir.

// 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");
}

Lembre-se de que o FirstOrDefault método retornará a primeira referência correspondente (uma planilha, neste caso) ou uma referência nula se nenhuma correspondência for encontrada. O código verifica a referência nula e lança uma exceção se você passou um nome de planilha inválido. Agora que você tem informações sobre a planilha, o código deve recuperar uma referência à parte correspondente da planilha. As informações da planilha que você já recuperou fornecem uma Id propriedade e, dada essa propriedade Id , o código pode recuperar uma referência à correspondência WorksheetPart chamando o método part GetPartById da pasta de trabalho.

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

Assim como ao localizar a planilha nomeada, ao localizar a célula nomeada, o código usa o Descendants método, procurando a primeira correspondência em que a CellReference propriedade é igual à especificada addressName parâmetro. Após essa chamada de método, a variável nomeada theCell conterá uma referência à célula ou conterá uma referência 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();

Recuperando o valor

Neste ponto, a variável nomeada theCell contém uma referência nula ou uma referência à célula que você solicitou. Se você examinar o conteúdo Open XML (ou seja, theCell.OuterXml) da célula, encontrará XML como o seguinte.

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

A InnerText propriedade contém o conteúdo da célula e, portanto, o próximo bloco de código recupera esse 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;

Agora, o método de exemplo deve interpretar o valor. Do jeito que está, o código lida com valores numéricos e de data, cadeia de caracteres e booleanos. Você pode estender o exemplo conforme necessário. O Cell tipo fornece uma DataType propriedade que indica o tipo dos dados dentro da célula. O valor da propriedade é null para os DataType tipos numérico e de data. Ele contém o valor CellValues.SharedString para cadeias de caracteres e CellValues.Boolean para valores booleanos. Se a DataType propriedade for nula, o código retornará o valor da célula (é um valor numérico). Caso contrário, o código continua ramificando com base no tipo de dados.

// 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)
    {

Se a DataType propriedade contiver CellValues.SharedString, o código deverá recuperar uma referência ao single SharedStringTablePart.

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

Em seguida, se a tabela de cadeia de caracteres existir (e se não existir, a pasta de trabalho está danificada e o código de exemplo retornará o índice para a tabela de cadeia de caracteres em vez da própria cadeia de caracteres), o código retornará a InnerText propriedade do elemento encontrado no índice especificado (primeiro convertendo a propriedade de valor em um número inteiro).

// 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;
}

Se a DataType propriedade contiver CellValues.Boolean, o código converterá o 0 ou 1 encontrado no valor da célula na cadeia de caracteres de texto apropriada.

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

Por fim, o procedimento retorna a variável value, que contém as informações solicitadas.

Código de exemplo

Veja a seguir o exemplo de código completo GetCellValue em C# e 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;
}

Confira também