获取电子表格文档中的列标题

本主题演示如何使用 Open XML SDK for Office 中的类以编程方式检索电子表格文档中的列标题。

spreadsheetML 文档的基本结构

文档的基本文档结构SpreadsheetML由 和 Sheet 元素组成Sheets,这些元素引用工作簿中的工作表。 将为每张工作表创建单独的 XML 文件。 例如, SpreadsheetML 具有两个 Workbook 工作表 MySheet1 和 MySheet2 的 位于 Workbook.xml 文件中,并在以下代码示例中显示。

    <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
    <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
        <sheets>
            <sheet name="MySheet1" sheetId="1" r:id="rId1" /> 
            <sheet name="MySheet2" sheetId="2" r:id="rId2" /> 
        </sheets>
    </workbook>

工作表 XML 文件包含一个或多个块级元素,如 SheetData 表示单元格表,并包含一个或多个 Row 元素。 包含 row 一个或多个 Cell 元素。 每个单元格都包含一个 CellValue 表示单元格值的元素。 例如, SpreadsheetML 工作簿中第一个工作表的 (在单元格 A1 中只有值 100) 位于 Sheet1.xml 文件中,并显示在以下代码示例中。

    <?xml version="1.0" encoding="UTF-8" ?> 
    <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
        <sheetData>
            <row r="1">
                <c r="A1">
                    <v>100</v> 
                </c>
            </row>
        </sheetData>
    </worksheet>

使用 Open XML SDK,可以创建使用与元素对应的 SpreadsheetML 强类型类的文档结构和内容。 可以在 命名空间中找到 DocumentFormat.OpenXML.Spreadsheet 这些类。 下表列出了对应于 、、sheetsworksheetsheetsheetData 元素的类的workbook类名。

SpreadsheetML 元素 Open XML SDK 类 说明
<workbook/> DocumentFormat.OpenXML.Spreadsheet.Workbook 主文档部件的根元素。
<sheets/> DocumentFormat.OpenXML.Spreadsheet.Sheets 块级结构(如工作表、文件版本和 ISO/IEC 29500 规范中指定的其他项)的容器。
<sheet/> DocumentFormat.OpenXml.Spreadsheet.Sheet 指向工作表定义文件的工作表。
<worksheet/> DocumentFormat.OpenXML.Spreadsheet。 Worksheet 包含工作表数据的工作表定义文件。
<sheetData/> DocumentFormat.OpenXML.Spreadsheet.SheetData 按行分组在一起的单元格表。
<row/> DocumentFormat.OpenXml.Spreadsheet.Row 单元格表中的行。
<c/> DocumentFormat.OpenXml.Spreadsheet.Cell 行中的单元格。
<v/> DocumentFormat.OpenXml.Spreadsheet.CellValue 单元格的值。

示例代码的工作方式

本操作方法中的代码由 Visual Basic) 中的三个方法 (函数组成: GetColumnHeadingGetColumnNameGetRowIndex。 最后两个方法是从 方法内部调用的 GetColumnHeading

方法 GetColumnName 采用单元格名称作为参数。 它分析单元格名称以获得列名,方法是创建一个正则表达式来匹配单元名称的列名部分。 有关正则表达式的详细信息,请参阅正则表达式语言元素

// Create a regular expression to match the column name portion of the cell name.
Regex regex = new Regex("[A-Za-z]+");
Match match = regex.Match(cellName);

return match.Value;

方法 GetRowIndex 采用单元格名称作为参数。 它分析单元格名称,并通过创建正则表达式以匹配单元格名称的行索引部分来获取行索引。

// Create a regular expression to match the row index portion the cell name.
Regex regex = new Regex(@"\d+");
Match match = regex.Match(cellName);

return uint.Parse(match.Value);

方法 GetColumnHeading 使用三个参数、源电子表格文件的完整路径、包含指定列的工作表的名称以及要获取标题的列中单元格的名称。

代码通过调用 GetColumnName 方法获取指定单元格的列的名称。 该代码还会获取列中的单元格,并使用 GetRowIndex 方法按行对其进行排序。

// Get the column name for the specified cell.
string columnName = GetColumnName(cellName);

// Get the cells in the specified column and order them by row.
IEnumerable<Cell> cells = worksheetPart.Worksheet.Descendants<Cell>().Where(c => string.Compare(GetColumnName(c.CellReference?.Value), columnName, true) == 0)
    .OrderBy(r => GetRowIndex(r.CellReference) ?? 0);

如果指定的列存在,它将使用 First 方法获取列中的第一个单元格。 第一个单元格包含标题。 否则,指定的列不存在,并且方法返回 null / Nothing

if (cells.Count() == 0)
{
    // The specified column does not exist.
    return null;
}

// Get the first cell in the column.
Cell headCell = cells.First();

如果单元格的内容存储在 对象中 SharedStringTablePart ,它将获取共享字符串项,并使用 方法返回列标题 Parse 的内容。 如果单元格的内容不在 对象中 SharedStringTable ,则返回单元格的内容。

// If the content of the first cell is stored as a shared string, get the text of the first cell
// from the SharedStringTablePart and return it. Otherwise, return the string value of the cell.
if (headCell.DataType is not null && headCell.DataType.Value == CellValues.SharedString && int.TryParse(headCell.CellValue?.Text, out int index))
{
    SharedStringTablePart shareStringPart = document.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
    SharedStringItem[] items = shareStringPart.SharedStringTable.Elements<SharedStringItem>().ToArray();

    return items[index].InnerText;
}
else
{
    return headCell.CellValue?.Text;
}

示例代码

以下是使用 C# 和 Visual Basic 编写的完整示例代码。

static string? GetColumnHeading(string docName, string worksheetName, string cellName)
{
    // Open the document as read-only.
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(docName, false))
    {
        IEnumerable<Sheet>? sheets = document.WorkbookPart?.Workbook.Descendants<Sheet>().Where(s => s.Name == worksheetName);

        if (sheets is null || sheets.Count() == 0)
        {
            // The specified worksheet does not exist.
            return null;
        }

        string? id = sheets.First().Id;

        if (id is null)
        {
            // The worksheet does not have an ID.
            return null;
        }

        WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart!.GetPartById(id);

        // Get the column name for the specified cell.
        string columnName = GetColumnName(cellName);

        // Get the cells in the specified column and order them by row.
        IEnumerable<Cell> cells = worksheetPart.Worksheet.Descendants<Cell>().Where(c => string.Compare(GetColumnName(c.CellReference?.Value), columnName, true) == 0)
            .OrderBy(r => GetRowIndex(r.CellReference) ?? 0);

        if (cells.Count() == 0)
        {
            // The specified column does not exist.
            return null;
        }

        // Get the first cell in the column.
        Cell headCell = cells.First();

        // If the content of the first cell is stored as a shared string, get the text of the first cell
        // from the SharedStringTablePart and return it. Otherwise, return the string value of the cell.
        if (headCell.DataType is not null && headCell.DataType.Value == CellValues.SharedString && int.TryParse(headCell.CellValue?.Text, out int index))
        {
            SharedStringTablePart shareStringPart = document.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
            SharedStringItem[] items = shareStringPart.SharedStringTable.Elements<SharedStringItem>().ToArray();

            return items[index].InnerText;
        }
        else
        {
            return headCell.CellValue?.Text;
        }
    }
}
// Given a cell name, parses the specified cell to get the column name.
static string GetColumnName(string? cellName)
{
    if (cellName is null)
    {
        return string.Empty;
    }

    // Create a regular expression to match the column name portion of the cell name.
    Regex regex = new Regex("[A-Za-z]+");
    Match match = regex.Match(cellName);

    return match.Value;
}

// Given a cell name, parses the specified cell to get the row index.
static uint? GetRowIndex(string? cellName)
{
    if (cellName is null)
    {
        return null;
    }

    // Create a regular expression to match the row index portion the cell name.
    Regex regex = new Regex(@"\d+");
    Match match = regex.Match(cellName);

    return uint.Parse(match.Value);
}

另请参阅

Open XML SDK 类库参考