Open XML SDKの単語ブックマークの後にOpenXmlElementを挿入します
-
06-07-2019 - |
質問
次のコードを使用して、Word文書内のブックマークにアクセスできました。
var res = from bm in mainPart.Document.Body.Descendants<BookmarkStart>()
where bm.Name == "BookmarkName"
select bm;
ここで、このブックマークの後に段落と表を挿入します。それ、どうやったら出来るの? (サンプルコードをいただければ幸いです)
解決
コード
ブックマークを取得したら、その親要素にアクセスして、その後に他のアイテムを追加できます。
using (WordprocessingDocument document = WordprocessingDocument.Open(@"C:\Path\filename.docx", true))
{
var mainPart = document.MainDocumentPart;
var res = from bm in mainPart.Document.Body.Descendants<BookmarkStart>()
where bm.Name == "BookmarkName"
select bm;
var bookmark = res.SingleOrDefault();
if (bookmark != null)
{
var parent = bookmark.Parent; // bookmark's parent element
// simple paragraph in one declaration
//Paragraph newParagraph = new Paragraph(new Run(new Text("Hello, World!")));
// build paragraph piece by piece
Text text = new Text("Hello, World!");
Run run = new Run(new RunProperties(new Bold()));
run.Append(text);
Paragraph newParagraph = new Paragraph(run);
// insert after bookmark parent
parent.InsertAfterSelf(newParagraph);
var table = new Table(
new TableProperties(
new TableStyle() { Val = "TableGrid" },
new TableWidth() { Width = 0, Type = TableWidthUnitValues.Auto }
),
new TableGrid(
new GridColumn() { Width = (UInt32Value)1018U },
new GridColumn() { Width = (UInt32Value)3544U }),
new TableRow(
new TableCell(
new TableCellProperties(
new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }),
new Paragraph(
new Run(
new Text("Category Name"))
)),
new TableCell(
new TableCellProperties(
new TableCellWidth() { Width = 4788, Type = TableWidthUnitValues.Dxa }),
new Paragraph(
new Run(
new Text("Value"))
))
),
new TableRow(
new TableCell(
new TableCellProperties(
new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }),
new Paragraph(
new Run(
new Text("C1"))
)),
new TableCell(
new TableCellProperties(
new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }),
new Paragraph(
new Run(
new Text("V1"))
))
));
// insert after new paragraph
newParagraph.InsertAfterSelf(table);
}
// close saves all parts and closes the document
document.Close();
}
上記のコードはそれを行う必要があります。ただし、いくつかの特別な状況について説明します。
ブックマークの親要素の後に挿入を試みることに注意してください。ブックマークがテーブル内の段落の一部である場合、どのような動作を期待しますか?そのテーブル内に、その直後に新しい段落とテーブルを追加する必要がありますか?それとも、そのテーブルの後に行うべきですか?
上記の質問がなぜ重要なのか疑問に思われるかもしれません。それはすべて、挿入が行われる場所に依存します。ブックマークの親がテーブル内にある場合、現在上記のコードはテーブル内にテーブルを配置しようとします。これで問題ありませんが、無効なOpenXml構造が原因でエラーが発生する可能性があります。理由は、挿入されたテーブルが元のテーブルのTableCellの最後の要素である場合、TableCellの終了タグの後にParagraph要素を追加する必要があるためです。 MS Wordで文書を開こうとしたときにこの問題が発生すると、すぐにこの問題を発見できます。
解決策は、テーブル内で実際に挿入を実行しているかどうかを判断することです。
そのために、上記のコードに(親変数の後に)追加できます:
var parent = bookmark.Parent; // bookmark's parent element
// loop till we get the containing element in case bookmark is inside a table etc.
// keep checking the element's parent and update it till we reach the Body
var tempParent = bookmark.Parent;
bool isInTable = false;
while (tempParent.Parent != mainPart.Document.Body)
{
tempParent = tempParent.Parent;
if (tempParent is Table && !isInTable)
isInTable = true;
}
// ...
newParagraph.InsertAfterSelf(table); // from above sample
// if bookmark is in a table, add a paragraph after table
if (isInTable)
table.InsertAfterSelf(new Paragraph());
これにより、エラーの発生が防止され、有効なOpenXmlが提供されます。 whileループのアイデアは、「はい」と答えた場合に使用できます。私の以前の質問に、上記のコードのようにテーブル内ではなく親テーブルの後に挿入を実行したかった。その場合は、上記の問題は問題ではなくなり、そのループとブール値を次のように置き換えることができます。
var parent = bookmark.Parent; // bookmark's parent element
while (parent.Parent != mainPart.Document.Body)
{
parent = parent.Parent;
}
これは、親がBodyレベルのメインの要素になるまで、親の再割り当てを続けます。したがって、ブックマークがテーブル内の段落にある場合、ParagraphからTableCell、TableRow、Tableの順に移動し、Tableの親がBodyであるため、そこで停止します。その時点でparent = Table要素であり、その後に挿入できます。
元の意図に応じて、いくつかの異なるアプローチをカバーする必要があります。試した後に説明が必要な場合はお知らせください。
ドキュメントリフレクター
GridColumn.Width
の値をどのように決定したのか疑問に思われるかもしれません。テーブルを作成し、Document Reflectorツールを使用して取得しました。 Open Xml SDKをインストールすると、生産性ツール(インストールした場合)は C:\ Program Files \ Open XML Format SDK \ V2.0 \ tools
(または同様のもの)にあります。
*。docx形式(またはOpen Xml形式のドキュメント)がどのように機能するかを知る最良の方法は、Document Reflectorツールで既存のファイルを開くことです。ドキュメントパーツをナビゲートし、複製するアイテムを見つけます。このツールは、ドキュメント全体の生成に使用される実際のコードを表示します。これは、アプリケーションにコピー/ペーストして同様の結果を生成できるコードです。通常、すべての参照IDは無視できます。あなたはそれを感じ取るために見てみる必要があります。
前述したように、上記の表のコードはサンプル文書から変更されています。 docxに簡単なテーブルを追加し、ツールで開いて、ツールで生成されたコードをコピーしました(クリーンアップするためにいくつかの余分なものを削除しました)。テーブルを追加するための実用的なサンプルが得られました。
書式付きの表やスタイル付きの段落など、何かを生成するコードの書き方を知りたい場合に特に役立ちます。
SDKに含まれる他のツールのスクリーンショットと情報については、次のリンクをご覧ください:概要XML SDK 2.0を開きます。。
コードスニペット