Получение заголовка столбца в документе электронной таблицы
В этом разделе показано, как использовать классы в пакете SDK Open XML для Office для программного извлечения заголовка столбца в документе электронной таблицы.
Базовая структура документа spreadsheetML
Базовая структура SpreadsheetML
документа состоит из Sheets элементов и Sheet , ссылающихся на листы в книге. Для каждого листа создается отдельный 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
для первого листа в книге, который имеет только значение 100 в ячейке A1, находится в файле 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>
С помощью пакета SDK Open XML можно создать структуру документа и содержимое, в котором используются строго типизированные классы, соответствующие SpreadsheetML
элементам. Эти классы можно найти в DocumentFormat.OpenXML.Spreadsheet
пространстве имен. В следующей таблице перечислены имена классов, которые соответствуют workbook
элементам , sheets
, sheet
, worksheet
и sheetData
.
Элемент SpreadsheetML | Класс пакета SDK Open XML | Описание |
---|---|---|
<workbook/> |
DocumentFormat.OpenXML.Spreadsheet.Workbook | Корневой элемент основной части документа. |
<sheets/> |
DocumentFormat.OpenXML.Spreadsheet.Sheets | Контейнер для структур уровня блока, таких как sheet, fileVersion и других, указанных в спецификации 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): GetColumnHeading
, GetColumnName
и GetRowIndex
. Последние два метода вызываются из 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);
}