Freigeben über


Abrufen der Werte von Zellen in einem Tabellenkalkulationsdokument

In diesem Thema wird gezeigt, wie Sie die Klassen im Open XML SDK für Office verwenden, um die Werte von Zellen in einem Tabellenkalkulationsdokument programmgesteuert abzurufen. Es enthält eine GetCellValue -Beispielmethode, um diese Aufgabe zu veranschaulichen.

GetCellValue-Methode

Sie können die GetCellValue-Methode zum Abrufen des Werts einer Zelle in einer Arbeitsmappe verwenden. Die Methode erfordert die folgenden drei Parameter:

  • Eine Zeichenfolge, die den Namen des zu überprüfenden Dokuments enthält.

  • Eine Zeichenfolge, die den Namen des zu überprüfenden Blatts enthält.

  • Eine Zeichenfolge, die die Zelladresse (z. B. A1, B12) enthält, aus der ein Wert abgerufen wird.

Die Methode gibt den Wert der angegebenen Zelle zurück, wenn sie gefunden werden konnte. Im folgenden Codebeispiel ist die Signatur der Methode dargestellt.

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

Funktionsweise des Codes

Der Code beginnt mit dem Erstellen einer Variablen für den Rückgabewert, und initialisiert sie bei Null.

string? value = null;

Zugreifen auf die Zelle

Als Nächstes öffnet der Code das Dokument mithilfe der Open-Methode, wodurch angegeben wird, dass das Dokument für schreibgeschützten Zugriff geöffnet werden soll (der letzte false-Parameter). Als Nächstes ruft der Code einen Verweis auf die Arbeitsmappe mithilfe der WorkbookPart-Eigenschaft des Dokuments ab.

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

Um die angeforderte Zelle zu finden, muss der Code zunächst einen Verweis auf das Blatt anhand des Namens abrufen. Der Code muss alle Nachfolger vom Typ „Blatt“ des Arbeitsmappenelements durchsuchen und die Name-Eigenschaft jedes Blatts überprüfen, das er findet. Beachten Sie, dass bei dieser Suche die Beziehungen der Arbeitsmappe durchsucht werden. Es wird nicht wirklich ein Teil eines Arbeitsblatts gesucht. Es wird ein Verweis auf ein Blatt gefunden, das Informationen wie den Namen und die Id des Blatts enthält. Die einfachste Möglichkeit hierfür ist die Verwendung einer LINQ-Abfrage, wie im folgenden Codebeispiel dargestellt.

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

Beachten Sie, dass die FirstOrDefault-Methode entweder den ersten übereinstimmenden Verweis (in diesem Fall ein Blatt) oder einen NULL-Verweis zurückgibt, wenn keine Übereinstimmung gefunden wurde. Der Code sucht nach dem NULL-Verweis und löst eine Ausnahme aus, wenn Sie einen ungültigen Blattnamen übergeben haben. Da Sie nun Informationen über das Blatt haben, muss der Code einen Verweis zu dem entsprechenden Teil des Arbeitsblatts abrufen. Die Blattinformationen, die Sie bereits abgerufen haben, lieferen eine Id-Eigenschaft. Anhand dieser Id-Eigenschaft kann der Code einen Verweis auf das entsprechende WorksheetPart abrufen, indem die GetPartById-Methode der Arbeitsmappe aufgerufen wird.

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

Genau wie beim Suchen nach dem benannten Blatt sucht der Code mithilfe der Descendants-Methode nach der benannten Zelle. Dabei wird nach der ersten Übereinstimmung gesucht, bei der die CellReference-Eigenschaft dem angegebenen addressName-Parameter gleicht. Nach diesem Methodenaufruf enthält die Variable mit dem Namen dieZelle einen Verweis auf die Zelle oder einen NULL-Verweis.

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

Abrufen des Werts

An diesem Punkt enthält die Variable namens DieZelle entweder einen NULL-Verweis oder einen Verweis auf die Zelle, die Sie angefordert haben. Wenn Sie den Open XML-Inhalt (d. h. theCell.OuterXml) für die Zelle untersuchen, finden Sie folgende XML.

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

Die InnerText -Eigenschaft enthält den Inhalt der Zelle, und daher ruft der nächste Codeblock diesen Wert ab.

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

Nun muss die Beispielmethode den Wert interpretieren. Dabei werden vom Code Zahlen- und Datumswerte sowie Zeichenfolgen und boolesche Werte verarbeitet. Sie können das Beispiel nach Bedarf erweitern. Der Cell-Typ stellt eine DataType-Eigenschaft bereit, die den Datentyp innerhalb der Zelle angibt. Der Wert der DataType-Eigenschaft ist für numerische Typen und Datumstypen Null. Sie enthält für Zeichenfolgen den Wert CellValues.SharedString und für boolesche Werte den Wert CellValues.Boolean. Wenn die DataType-Eigenschaft Null ist, gibt der Code den Wert der Zelle zurück (es ist ein Zahlenwert). Andernfalls setzt der Code den Vorgang durch Verzweigen anhand des Datentyps fort.

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

Wenn die DataType-Eigenschaft den Wert CellValues.SharedString enthält, muss der Code einen Verweis auf den einzelnen SharedStringTablePart abrufen.

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

Wenn die Zeichenfolgentabelle vorhanden ist (wenn sie nicht vorhanden ist, ist die Arbeitsmappe beschädigt, und der Beispielcode gibt den Index in der Zeichenfolgentabelle anstelle der Zeichenfolge selbst zurück) gibt der Code als Nächstes die InnerText-Eigenschaft des Elements zurück, das er am angegebenen Index findet (zuerst wird der Eigenschaftswert in eine ganze Zahl konvertiert).

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

Wenn die DataType-Eigenschaft den Wert CellValues.Boolean enthält, konvertiert der Code die 0 oder 1, die er im Zellenwert findet, in die entsprechende Textzeichenfolge.

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

Schließlich gibt die Prozedur die Variable value zurück, die die angeforderten Informationen enthält.

Beispielcode

Es folgt ein vollständiges GetCellValue-Codebeispiel in C# und 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;
}