Obter os valores das células num documento de folha de cálculo
Este tópico mostra como utilizar as classes no SDK Open XML para o Office para obter programaticamente os valores das células num documento de folha de cálculo. Contém um método de exemplo GetCellValue
para ilustrar esta tarefa.
Método GetCellValue
Pode utilizar o GetCellValue
método para obter o valor de uma célula num livro. O método requer os três parâmetros seguintes:
Uma cadeia que contém o nome do documento a examinar.
Uma cadeia que contém o nome da folha a examinar.
Uma cadeia que contém o endereço da célula (como A1, B12) a partir do qual obter um valor.
O método devolve o valor da célula especificada, caso possa ser encontrado. O seguinte exemplo de código mostra a assinatura do método.
static string GetCellValue(string fileName, string sheetName, string addressName)
Como Funciona o Código
O código começa por criar uma variável para manter o valor devolvido e inicializa-o como nulo.
string? value = null;
Aceder à Célula
Em seguida, o código abre o documento com o Open método , indicando que o documento deve estar aberto para acesso só de leitura (o parâmetro final false
). Em seguida, o código obtém uma referência à parte do livro com 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 pedida, o código tem primeiro de obter uma referência para a folha, dado o respetivo nome. O código tem de procurar todos os descendentes do tipo de folha do elemento de livro da parte do livro e examinar a Name propriedade de cada folha que encontrar. Tenha em atenção que esta pesquisa analisa as relações do livro e não encontra realmente uma peça de folha de cálculo. Localiza uma referência a um Sheet, que contém informações como o nome e Id a folha. A forma mais simples de o fazer é utilizar uma consulta LINQ, conforme mostrado no exemplo de código seguinte.
// 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");
}
Tenha em atenção que o FirstOrDefault método devolve a primeira referência correspondente (uma folha, neste caso) ou uma referência nula se não for encontrada nenhuma correspondência. O código verifica a referência nula e gera uma exceção se tiver transmitido um nome de folha inválido. Agora que tem informações sobre a folha, o código tem de obter uma referência à parte da folha de cálculo correspondente. As informações da folha que já obteve fornecem uma Id propriedade e, tendo em conta essa propriedade de ID , o código pode obter uma referência ao correspondente WorksheetPart ao chamar o método de peça GetPartById do livro.
// Retrieve a reference to the worksheet part.
WorksheetPart wsPart = (WorksheetPart)wbPart!.GetPartById(theSheet.Id!);
Tal como ao localizar a folha com nome, ao localizar a célula com nome, o código utiliza o Descendants método , procurando a primeira correspondência em que a CellReference propriedade é igual à especificada
addressName
parâmetro. Após esta chamada de método, a variável com o nome 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();
A obter o Valor
Neste momento, a variável com o nome theCell
contém uma referência nula ou uma referência à célula que pediu. Se 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, por isso, o bloco de código seguinte obtém 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;
Agora, o método de exemplo tem de interpretar o valor. Tal como está, o código processa valores numéricos e de data, cadeia e booleanos. Pode expandir o exemplo conforme necessário. O Cell tipo fornece uma DataType propriedade que indica o tipo de dados na célula. O valor da DataType
propriedade é nulo para tipos numéricos e de data. Contém o valor CellValues.SharedString
para cadeias e CellValues.Boolean
para valores booleanos. Se a DataType
propriedade for nula, o código devolve o valor da célula (é um valor numérico). Caso contrário, o código continua a ramificar 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 tem de obter uma referência para o único 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 cadeias existir (e se não existir, o livro está danificado e o código de exemplo devolve o índice na tabela de cadeias em vez da própria cadeia), o código devolve a InnerText
propriedade do elemento que encontra no índice especificado (primeiro convertendo a propriedade do valor num 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 converte o 0 ou 1 que encontra no valor da célula na cadeia de texto adequada.
switch (value)
{
case "0":
value = "FALSE";
break;
default:
value = "TRUE";
break;
}
Por fim, o procedimento devolve a variável value
, que contém as informações pedidas.
Código de exemplo
Segue-se 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;
}