コンテンツ コントロール タイプ
Word 文書の挿入ポイントに応じて、次の 2 種類のコンテンツ コントロールが作成されます。
トップレベル (段落と同じレベル)
ネスト (通常は既存の段落内)
紛らわしいことに、XML では両方の型が としてタグ付けされて<sdt>...</sdt>
いますが、基礎となる openXML クラスは異なります。トップレベルの場合、ルートはSdtBlock
で、コンテンツはSdtContentBlock
です。入れ子の場合はSdtRun
&SdtContentRun
です。
両方のタイプ、つまりすべてのコンテンツ コントロールを取得するには、共通の基本クラスを介して反復しSdtElement
、タイプを確認することをお勧めします。
List<SdtElement> sdtList = document.Descendants<SdtElement>().ToList();
foreach( SdtElement sdt in sdtList )
{
if( sdt is SdtRun )
{
; // process nested sdts
}
if( sdt is SdtBlock )
{
; // process top-level sdts
}
}
ドキュメント テンプレートの場合、すべてのコンテンツ コントロールを処理する必要があります。複数のコンテンツ コントロールが同じタグ名 (例: 顧客名) を持つことはよくあることであり、通常、これらすべてを実際の顧客名に置き換える必要があります。
コンテンツ コントロール タグ名
content-control tag-name は決して分割されません。
XML では、これは次のとおりです。
<w:sdt>
...
<w:sdtPr>
...
<w:tag w:val="customer-name"/>
タグ名は決して分割されないため、常に直接一致して見つけることができます。
List<SdtElement> sdtList = document.Descendants<SdtElement>().ToList();
foreach( SdtElement sdt in sdtList )
{
if( sdt is SdtRun )
{
String tagName = sdt.SdtProperties.GetFirstChild<Tag>().Val;
if( tagName == "customer-name" )
{
; // get & replace placeholder with actual value
}
明らかに、上記のコードでは、それぞれの異なるタグ名に対応する実際の値を取得するためのより洗練されたメカニズムが必要になります。
コンテンツ コントロール テキスト
コンテンツ コントロール内では、レンダリングされたテキストが複数のランに分割されることは非常に一般的です (各ランが同じプロパティを持っているにもかかわらず)。
とりわけ、これはスペル/文法チェッカーと編集試行回数によって引き起こされます。[customer-name] などの区切り文字が使用されている場合、テキスト分割はより一般的です。
これが重要な理由は、XML をチェックしないと、プレースホルダー テキストが分割されていないことを保証できないため、見つけて置き換えることができないからです。
推奨されるアプローチの 1 つ
推奨されるアプローチの 1 つは、最上位および/またはネストされたプレーンテキストのコンテンツ コントロールのみを使用することです。
タグ名で content-control を見つける
書式設定された段落を挿入するか、コンテンツ コントロールの後に実行します
コンテンツ コントロールを削除する
List<SdtElement> sdtList = document.Descendants<SdtElement>().ToList();
foreach( SdtElement sdt in sdtList )
{
if( sdt is SdtRun )
{
String tagName = sdt.SdtProperties.GetFirstChild<Tag>().Val;
String newText = "new text"; // eg GetTextByTag( tagName );
// should use a style or common run props
RunProperties runProps = new RunProperties();
runProps.Color = new Color () { Val = "000000" };
runProps.FontSize = new FontSize() { Val = "23" };
runProps.RunFonts = new RunFonts() { Ascii = "Calibri" };
Run run = new Run();
run.Append( runProps );
run.Append( new Text( newText ) );
sdt.InsertAfterSelf( run );
sdt.Remove();
}
if( sdt is SdtBlock )
{
; // add paragraph
}
}
トップレベルの型の場合、段落を挿入する必要があります。
このアプローチでは、コンテンツ コントロールは、(タグ名によって) 確実に見つかるプレースホルダーとしてのみ使用され、適切なテキスト (一貫してフォーマットされている) に完全に置き換えられます。
また、これにより、コンテンツ コントロール テキストをフォーマットする必要がなくなります (分割されて見つからない可能性があります)。
タグ名に適切な命名規則 (Xpath 式など) を使用すると、他の XML ドキュメントを使用してテンプレートに入力するなど、さらに可能性が広がります。