Поделиться через


Получение значений ячеек в документе электронной таблицы

В этом разделе показано, как использовать классы в пакете SDK Open XML для Office для программного извлечения значений ячеек в документе электронной таблицы. Он содержит пример GetCellValue метода для иллюстрации этой задачи.

Метод GetCellValue

Метод можно использовать для GetCellValue получения значения ячейки в книге. Он принимает следующие три параметра:

  • строка, содержащая имя документа для просмотра;

  • строка, содержащая имя листа для просмотра;

  • строка, содержащая адрес ячейки (например, A1 или B12), из которой нужно извлечь значение.

Метод возвращает значение указанной ячейки, если ее удалось найти. В следующем примере кода показана сигнатура метода.

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

Как работает код

Сначала код создает переменную для хранения возвращаемого значения, которой присваивается значение NULL.

string? value = null;

Доступ к ячейке

Затем код открывает документ с помощью Open метода , указывающего, что документ должен быть открыт для доступа только для чтения (последний false параметр). Затем код получает ссылку на часть книги с помощью WorkbookPart свойства документа.

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

Чтобы найти запрошенную ячейку, сначала необходимо получить ссылку на лист по его имени. Код должен выполнить поиск всех потомков листа элемента книги части книги и изучить Name свойство каждого листа, который он находит. Имейте в виду, что при поиске код просматривает связи книги, а не фактически ищет часть листа. Он находит ссылку на Sheet, которая содержит такие сведения, как имя и Id лист. Самый простой способ добиться этого — использовать запрос LINQ, как показано в следующем примере кода.

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

Имейте в FirstOrDefault виду, что метод возвращает либо первую соответствующую ссылку (в данном случае лист), либо пустую ссылку, если совпадение не найдено. Код проверяет наличие пустой ссылки и вызывает исключение, если передано неверное имя листа. После получения сведений о листе код должен получить ссылку на соответствующую часть листа. Сведения на листе, которые вы уже получили, предоставляют Id свойство, а учитывая это свойство Id , код может получить ссылку на соответствующий WorksheetPart , вызвав метод части GetPartById книги.

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

Так же, как при поиске именованного листа, при поиске именованной ячейки код использует метод , в котором выполняется Descendants поиск первого совпадения, в котором CellReference свойство равно указанному. addressName параметр. После этого вызова метода переменная theCell будет содержать ссылку на ячейку или пустую ссылку.

// 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();

Извлечение значения

На этом этапе переменная с именем theCell содержит либо пустую ссылку, либо ссылку на запрошенную ячейку. Если вы изучите содержимое Open XML (т. е. theCell.OuterXml) для ячейки, вы увидите XML-код, например следующий.

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

Свойство InnerText содержит содержимое ячейки, поэтому следующий блок кода получает это значение.

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

Теперь примеру метода необходимо интерпретировать значение. Код обрабатывает числовые, строковые и логические значения, а также даты. Возможности примера при необходимости можно расширить. Тип Cell предоставляет DataType свойство, указывающее тип данных в ячейке. Значение DataType свойства равно NULL для числовых типов и типов даты. Он содержит значение CellValues.SharedString для строк и CellValues.Boolean для логических значений. DataType Если свойство имеет значение NULL, код возвращает значение ячейки (это числовое значение). В противном случае код переходит по ветвлению на основе типа данных.

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

DataType Если свойство содержит CellValues.SharedString, код должен получить ссылку на один объект SharedStringTablePart.

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

Далее, если таблица строк существует (а если нет, книга повреждена, и пример кода возвращает индекс в таблицу строк, а не саму строку), код возвращает InnerText свойство элемента, который он находит по указанному индексу (сначала преобразовав свойство value в целое число).

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

DataType Если свойство содержит CellValues.Boolean, код преобразует значение 0 или 1, которое он находит в значении ячейки, в соответствующую текстовую строку.

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

Наконец, процедура возвращает переменную value, которая содержит запрошенные сведения.

Пример кода

Ниже приведен полный GetCellValue пример кода на C# и 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;
}

См. также