前回の残件である「セルに文字列をセットする」方法について説明します。
手順としては(おさらいになりますが)以下のようになります。
- SharedStringパーツからセットしたい文字列を検索して、そのインデックス番号(n番目のsi要素)を取得する。
(このときセットした文字列をもつsi要素が存在しなければ新たにsi要素を追加し、そのインデックス番号を取得する。) - 取得したインデックスを、文字列をセットしたいc要素の値として指定する
文字列をセットするためには、前回のプログラムの57行目を以下のように書き換えます。
cell.DataType = CellValues.SharedString;
cell.CellValue = new CellValue(InsertSharedStringItem("abc", bookPart.SharedStringTablePart).ToString());
ここでInsertSharedStringItemの定義はMicrosoft Learnにあります。
(以下引用します)
// Given text and a SharedStringTablePart, creates a SharedStringItem with the specified text
// and inserts it into the SharedStringTablePart. If the item already exists, returns its index.
private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
{
// If the part does not contain a SharedStringTable, create one.
if (shareStringPart.SharedStringTable == null)
{
shareStringPart.SharedStringTable = new SharedStringTable();
}
int i = 0;
// Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>())
{
if (item.InnerText == text)
{
return i;
}
i++;
}
// The text does not exist in the part. Create the SharedStringItem and return its index.
shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
shareStringPart.SharedStringTable.Save();
return i;
}
InsertSharedStringItemは先の手順2を行い、そのインデックスを返します。 プログラムを実行するとセルA6に文字列"abc"が入力されます。
実用的な側面から #
上記のInsertSharedStringItemの実装はあくまでサンプルコードとしての実装であって、これをそのまま実際のアプリケーションで使おうとするといろいろと問題があります。(問題というには大げさかもしれませんが…)
フリガナの扱い #
先ほどは文字"abc"をセットしましたが、代わりに"東京特許許可局"とするとどうなるでしょうか?
…意図したとおりにセルA6に"東京特許許可局"が入っています。しかしProductivity Toolでworksheetパーツの中身を覗いてみると以下のようになっています。
同じ"東京特許許可局"にもかかわらず、別のインデックスが振られています。
別のインデックスが割り振られる理由は「フリガナ(ルビ)の存在」によります。SharedStringパーツを見てみると、以下のようになっています。
インデックスが1(2番目)のsi要素にはフリガナ「トウキョウトッキョキョカキョク」があります。それゆえ、InsertSharedStringItemの定義の16行目のitem.InnerTextの値は「東京特許許可局トウキョウトッキョキョカキョク」となってしまい、「東京特許許可局」と一致しません。その結果、新たなsi要素(3番目のsi要素 / インデックス2)が作成されてしまいます。
フリガナのことだけを考えるならば、InsertSharedStringItemの定義の16行目を以下のように書き換えることでセルA2, A6ともに同じインデックスを割り振らせることができます。
|
|
文字の一部にセットされた書式の扱い #
InsertSharedStringItemの定義の16行目を上記のように書き換えることで、フリガナの問題は解決されますが、また別の問題が生じます。
セルA2の内容を「東京特許許可局」のように、一部の書式を変更(一部の文字を赤色に)します。そしてInsertSharedStringItemの定義の16行目を上記のように書き換えてプログラムを実行すると、やはり新たなsi要素を作ってしまいます。
実装するアプリケーションの用途によっては、これはこれで期待どおりの振る舞いかもしれません。
文字の一部にセットされた書式はsi要素の中に定義されるので、こういった書式についてもコントロールしたいならば、InsertSharedStringItemの引数を工夫する必要があります。
書式を引数で渡す…というのは限界がありますので、セルにセットする「文字列」を引き渡すのではなくsi要素(DocumentFormat.OpenXml.Spreadsheet.SharedStringItem)を引き渡すようにするとうまくいきます。(引き渡すべきSharedStringItemインスタンスをInsertSharedStringItemの呼び出し側で準備する手間が増えますが…)