スプレッドシート ドキュメント内のセルからテキストを削除する
このトピックでは、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 | セルの値。 |
サンプル コードのしくみ
次のコード例では、 SpreadsheetDocument ドキュメント パッケージ内のセルからテキストを削除します。 次に、スプレッドシート ドキュメント内の他のセルが行から削除されたテキストを引き続き参照しているかどうかを確認し、そうでない場合は、Remove メソッドを使用してSharedStringTablePart オブジェクトからテキストを削除します。 次に、RemoveSharedStringItem
メソッドを呼び出して、SharedStringTablePart
オブジェクトをクリーンします。
// Given a document, a worksheet name, a column name, and a one-based row index,
// deletes the text from the cell at the specified column and row on the specified worksheet.
static void DeleteTextFromCell(string docName, string sheetName, string colName, uint rowIndex)
{
// Open the document for editing.
using (SpreadsheetDocument document = SpreadsheetDocument.Open(docName, true))
{
IEnumerable<Sheet>? sheets = document.WorkbookPart?.Workbook?.GetFirstChild<Sheets>()?.Elements<Sheet>()?.Where(s => s.Name is not null && s.Name == sheetName);
if (sheets is null || sheets.Count() == 0)
{
// The specified worksheet does not exist.
return;
}
string? relationshipId = sheets.First()?.Id?.Value;
if (relationshipId is null)
{
// The worksheet does not have a relationship ID.
return;
}
WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart!.GetPartById(relationshipId);
// Get the cell at the specified column and row.
Cell? cell = GetSpreadsheetCell(worksheetPart.Worksheet, colName, rowIndex);
if (cell is null)
{
// The specified cell does not exist.
return;
}
cell.Remove();
}
}
次のコード例では、列名と行インデックスで指定されたセルが存在することを確認します。 その場合、コードはセルを返します。それ以外の場合は、 null
を返します。
// Given a worksheet, a column name, and a row index, gets the cell at the specified column and row.
static Cell? GetSpreadsheetCell(Worksheet worksheet, string columnName, uint rowIndex)
{
IEnumerable<Row>? rows = worksheet.GetFirstChild<SheetData>()?.Elements<Row>().Where(r => r.RowIndex is not null && r.RowIndex == rowIndex);
if (rows is null || rows.Count() == 0)
{
// A cell does not exist at the specified row.
return null;
}
IEnumerable<Cell> cells = rows.First().Elements<Cell>().Where(c => string.Compare(c.CellReference?.Value, columnName + rowIndex, true) == 0);
if (cells.Count() == 0)
{
// A cell does not exist at the specified column, in the specified row.
return null;
}
return cells.FirstOrDefault();
}
次のコード例では、スプレッドシート ドキュメント内の他のセルが、 shareStringId
パラメーターで指定されたテキストを参照しているかどうかを確認します。 テキストが参照されていない場合は、 SharedStringTablePart
オブジェクトから削除します。 これを行うには、削除するテキストの ID を表すパラメーターと、 SpreadsheetDocument
ドキュメント パッケージを表すパラメーターを渡します。 次に、各 Worksheet
オブジェクトを反復処理し、各 Cell
オブジェクトの内容を共有文字列 ID と比較します。 スプレッドシート ドキュメント内の他のセルが引き続き SharedStringItem オブジェクトを参照している場合は、 SharedStringTablePart
オブジェクトから項目を削除しません。 スプレッドシート ドキュメント内の他のセルが SharedStringItem
オブジェクトを参照しなくなった場合は、 SharedStringTablePart
オブジェクトから項目を削除します。 次に、各 Worksheet
オブジェクトと Cell
オブジェクトを反復処理し、共有文字列参照を更新します。
// Given a shared string ID and a SpreadsheetDocument, verifies that other cells in the document no longer
// reference the specified SharedStringItem and removes the item.
static void RemoveSharedStringItem(int shareStringId, SpreadsheetDocument document)
{
bool remove = true;
if (document.WorkbookPart is null)
{
return;
}
foreach (var part in document.WorkbookPart.GetPartsOfType<WorksheetPart>())
{
var cells = part.Worksheet.GetFirstChild<SheetData>()?.Descendants<Cell>();
if (cells is null)
{
continue;
}
foreach (var cell in cells)
{
// Verify if other cells in the document reference the item.
if (cell.DataType is not null &&
cell.DataType.Value == CellValues.SharedString &&
cell.CellValue?.Text == shareStringId.ToString())
{
// Other cells in the document still reference the item. Do not remove the item.
remove = false;
break;
}
}
if (!remove)
{
break;
}
}
// Other cells in the document do not reference the item. Remove the item.
if (remove)
{
SharedStringTablePart? shareStringTablePart = document.WorkbookPart.SharedStringTablePart;
if (shareStringTablePart is null)
{
return;
}
SharedStringItem item = shareStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(shareStringId);
if (item is not null)
{
item.Remove();
// Refresh all the shared string references.
foreach (var part in document.WorkbookPart.GetPartsOfType<WorksheetPart>())
{
var cells = part.Worksheet.GetFirstChild<SheetData>()?.Descendants<Cell>();
if (cells is null)
{
continue;
}
foreach (var cell in cells)
{
if (cell.DataType is not null && cell.DataType.Value == CellValues.SharedString && int.TryParse(cell.CellValue?.Text, out int itemIndex))
{
if (itemIndex > shareStringId)
{
cell.CellValue.Text = (itemIndex - 1).ToString();
}
}
}
}
}
}
}
サンプル コード
以下に、C# と Visual Basic の両方の完全なサンプル コードを示します。
static void DeleteTextFromCell(string docName, string sheetName, string colName, uint rowIndex)
{
// Open the document for editing.
using (SpreadsheetDocument document = SpreadsheetDocument.Open(docName, true))
{
IEnumerable<Sheet>? sheets = document.WorkbookPart?.Workbook?.GetFirstChild<Sheets>()?.Elements<Sheet>()?.Where(s => s.Name is not null && s.Name == sheetName);
if (sheets is null || sheets.Count() == 0)
{
// The specified worksheet does not exist.
return;
}
string? relationshipId = sheets.First()?.Id?.Value;
if (relationshipId is null)
{
// The worksheet does not have a relationship ID.
return;
}
WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart!.GetPartById(relationshipId);
// Get the cell at the specified column and row.
Cell? cell = GetSpreadsheetCell(worksheetPart.Worksheet, colName, rowIndex);
if (cell is null)
{
// The specified cell does not exist.
return;
}
cell.Remove();
}
}
// Given a worksheet, a column name, and a row index, gets the cell at the specified column and row.
static Cell? GetSpreadsheetCell(Worksheet worksheet, string columnName, uint rowIndex)
{
IEnumerable<Row>? rows = worksheet.GetFirstChild<SheetData>()?.Elements<Row>().Where(r => r.RowIndex is not null && r.RowIndex == rowIndex);
if (rows is null || rows.Count() == 0)
{
// A cell does not exist at the specified row.
return null;
}
IEnumerable<Cell> cells = rows.First().Elements<Cell>().Where(c => string.Compare(c.CellReference?.Value, columnName + rowIndex, true) == 0);
if (cells.Count() == 0)
{
// A cell does not exist at the specified column, in the specified row.
return null;
}
return cells.FirstOrDefault();
}
// Given a shared string ID and a SpreadsheetDocument, verifies that other cells in the document no longer
// reference the specified SharedStringItem and removes the item.
static void RemoveSharedStringItem(int shareStringId, SpreadsheetDocument document)
{
bool remove = true;
if (document.WorkbookPart is null)
{
return;
}
foreach (var part in document.WorkbookPart.GetPartsOfType<WorksheetPart>())
{
var cells = part.Worksheet.GetFirstChild<SheetData>()?.Descendants<Cell>();
if (cells is null)
{
continue;
}
foreach (var cell in cells)
{
// Verify if other cells in the document reference the item.
if (cell.DataType is not null &&
cell.DataType.Value == CellValues.SharedString &&
cell.CellValue?.Text == shareStringId.ToString())
{
// Other cells in the document still reference the item. Do not remove the item.
remove = false;
break;
}
}
if (!remove)
{
break;
}
}
// Other cells in the document do not reference the item. Remove the item.
if (remove)
{
SharedStringTablePart? shareStringTablePart = document.WorkbookPart.SharedStringTablePart;
if (shareStringTablePart is null)
{
return;
}
SharedStringItem item = shareStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(shareStringId);
if (item is not null)
{
item.Remove();
// Refresh all the shared string references.
foreach (var part in document.WorkbookPart.GetPartsOfType<WorksheetPart>())
{
var cells = part.Worksheet.GetFirstChild<SheetData>()?.Descendants<Cell>();
if (cells is null)
{
continue;
}
foreach (var cell in cells)
{
if (cell.DataType is not null && cell.DataType.Value == CellValues.SharedString && int.TryParse(cell.CellValue?.Text, out int itemIndex))
{
if (itemIndex > shareStringId)
{
cell.CellValue.Text = (itemIndex - 1).ToString();
}
}
}
}
}
}
}