スプレッドシート ドキュメントで列見出しを取得する
このトピックでは、Open XML SDK for Office のクラスを使用して、プログラムによってスプレッドシート ドキュメント内の列見出しを取得する方法について説明します。
spreadsheetML ドキュメントの基本的な構造
SpreadsheetML
ドキュメントの基本的なドキュメント構造は、ブック内のワークシートを参照するSheets要素とSheet要素で構成されます。 ワークシートごとに、それぞれの XML ファイルが作成されます。 たとえば、MySheet1 と MySheet2 という名前の 2 つのワークシートがあるWorkbookのSpreadsheetML
は、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 1 つ以上のブロック レベル要素が含まれており、1 つ以上の Row 要素が含まれています。
row
には、1 つ以上のCell要素が含まれています。 各セルには、セルの値を表す CellValue 要素が含まれています。 たとえば、セル A1 の値が 100 しかないブックの最初のワークシートの SpreadsheetML
は、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
名前空間にあります。 次の表に、 workbook
、 sheets
、 sheet
、 worksheet
、 sheetData
の各要素に対応するクラスのクラス名を示します。
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 | セルの値。 |
サンプル コードの動作のしくみ
このハウツーのコードは、 GetColumnHeading
、 GetColumnName
、 GetRowIndex
の 3 つのメソッド (Visual Basic の関数) で構成されます。 最後の 2 つのメソッドは、 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
メソッドでは、3 つのパラメーター、ソース スプレッドシート ファイルへの完全なパス、指定した列を含むワークシートの名前、見出しを取得する列内のセルの名前を使用します。
コードは、 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);
}