はじめに
先月(2021/08)、技術評論社より『C#コードレシピ集』を出版しました。この本には、385のコードレシピが掲載されています。執筆している段階では385を超えるレシピを予定していたのですが、ページ数の関係(この本700ページを超える分厚い本です)でいくつかのレシピは没にしています。その中にOpen XMLを使ってExcelを操作するものがあります。そのまま眠らせてしまうのは残念ので、Qiitaでこのレシピを5回に分けて紹介しています。
- OpenXMLでExcelファイルを操作しよう (1) - Excelファイルを新規作成したい
- OpenXMLでExcelファイルを操作しよう (2) - セルに値を設定したい ← 今ここ
- OpenXMLでExcelファイルを操作しよう (3) - セルの値を読み込みたい
- OpenXMLでExcelファイルを操作しよう (4) - 全てのセルの値を取得したい
- OpenXMLでExcelファイルを操作しよう (5) - セルに書式を設定したい
コードレシピの環境は、C#9.0 + .NET 5 のコンソールアプリケーションです。
なお、『C#コードレシピ集』では、NPOIを使ってエクセルファイルを操作するレシピを掲載しています。
定義するメソッド
OpneXMLを利用してセルに値を設定するには、「シートを選択」「セルオブジェクトを作成」「セルに値を設定」という3つの手順を踏みます。
前回定義した、MyExcelBookクラスにこれらの機能を実装してみます。ここでは以下の4つのメソッドを定義しています。
メソッド | 機能 |
---|---|
SelectSheet | シートを選択 |
CreateCell | セルオブジェクトの作成、すでに存在している場合はそのセルを返す |
SetValueAtCell | セルに値を設定 |
SetValue | セルを作成し値を設定する。CreateCell, SetValueAtCellを連続して呼び出す |
最後のSetValueメソッドは、CreateCell、SetValueAtCellのふたつのメソッドを連続して呼び出すことで、簡単にセルに値を設定する機能を呼び出せるようにしたものです。すでにCellが存在している場合は、上書きされます。
MyExcelBookクラス
では、MyExcelBookクラスを示します。
sealed class MyExcelBook : IDisposable {
private MyExcelBook() { }
public void Dispose() => _document?.Dispose();
private SpreadsheetDocument _document;
private WorkbookPart _workbookpart;
private WorksheetPart _worksheetPart;
private Sheets _sheets;
public static MyExcelBook CreateBook(string filepath) {
var book = new MyExcelBook();
// Excelのドキュメントを新規に作成する
book._document = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook);
// ドキュメントにワークブックを追加する
book._workbookpart = book._document.AddWorkbookPart();
book._workbookpart.Workbook = new Workbook();
// ワークブックにシートの入れ物を追加する
book._sheets = book._workbookpart.Workbook.AppendChild<Sheets>(new Sheets());
return book;
}
public void Save() {
_workbookpart.Workbook.Save();
_document.Close();
}
public void CreateSheet(string sheetname) {
// シート作成のための準備
_worksheetPart = _workbookpart.AddNewPart<WorksheetPart>();
_worksheetPart.Worksheet = new Worksheet(new SheetData());
// シートを作成し追加する
var max = (uint)(_sheets.Count() + 1);
var sheet = new Sheet {
Id = _workbookpart.GetIdOfPart(_worksheetPart),
SheetId = max,
Name = sheetname
};
_sheets.Append(sheet);
}
// 以降が追加したメンバー
// シートを選択する
public void SelectSheet(string sheetName) {
// workbookから指定したシートを見つける
var theSheet = _workbookpart.Workbook.Descendants<Sheet>().
Where(s => s.Name == sheetName).FirstOrDefault();
if (theSheet == null)
throw new ArgumentException("sheetName");
// WorkSheetPartを取り出す。これが以降の操作で必要
_worksheetPart = (WorksheetPart)(_workbookpart.GetPartById(theSheet.Id));
}
// セルを作成。存在していたらそのセルを返す
public Cell CreateCell(string columnName, uint rowIndex) {
// SheetDataを見つける
var worksheet = _worksheetPart.Worksheet;
var sheetData = worksheet.GetFirstChild<SheetData>();
// 行を見つける
var row = sheetData.Elements<Row>().FirstOrDefault(r => r.RowIndex == rowIndex);
if (row == null) {
// 行がなければ追加する
row = new Row { RowIndex = rowIndex };
sheetData.Append(row);
}
// その行の指定したカラムのセルを取り出す
var cellReference = columnName + rowIndex;
var cell = row.Elements<Cell>().FirstOrDefault(c => c.CellReference.Value == cellReference);
if (cell != null)
return cell;
// セルがなければセルを追加する
var refCell = row.Elements<Cell>()
.FirstOrDefault(c => string.Compare(c.CellReference.Value, cellReference, true) > 0);
var newCell = new Cell() {
CellReference = cellReference
};
row.InsertBefore(newCell, refCell);
return newCell;
}
// 指定したセルに値を設定する
public void SetValueAtCell(Cell cell, string text) {
cell.CellValue = new CellValue(text);
cell.DataType = new EnumValue<CellValues>(CellValues.String);
}
// column, rowで指定したセルに値を設定する。
public void SetValue(string text, string columnName, uint rowIndex) {
Cell cell = CreateCell(columnName, rowIndex);
SetValueAtCell(cell, text);
}
}
MyExcelBookクラスを使って、セルに値を設定する
以下、エクセルのBookを新規作成し、sheet1のセルA1, B2, C3に値を設定している例です。
using var book = MyExcelBook.CreateBook("example.xlsx");
book.CreateSheet("sheet1");
book.SelectSheet("sheet1");
book.SetValue("Text 1", "A", 1);
book.SetValue("Text 2", "B", 2);
book.SetValue("Text 3", "C", 3);
book.Save();
実行結果
以下のようなExcelファイルが作成されます。