ワープロ ドキュメントでスタイル パーツを置換する
このトピックでは、Open XML SDK for Office のクラスを使用して、プログラムによってワープロ ドキュメント内のスタイルを別のワープロ ドキュメントのスタイルに置き換える方法について説明します。 このタスクを示す ReplaceStyles
メソッドの例と、 ReplaceStylesPart
と ExtractStylesPart
サポート メソッドが含まれています。
スタイルの格納域について
拡張子が .docx のファイルなど、ワープロ ドキュメント パッケージは、実際には、複数のパーツで構成される .zip ファイルです。 各パーツは、外部ファイルのようなものと考えることができます。 パーツには特定のコンテンツ タイプがあり、種類に応じて、外部 XML ファイル、バイナリ ファイル、イメージ ファイルなどのファイルのコンテンツに等しいコンテンツを格納できます。 Open XML ドキュメントを .zip ファイルに格納する方法を定義している標準は、Open Packaging Conventions と呼ばれています。 Open Packaging Conventions の詳細については、「ISO/IEC 29500-2」を参照してください。
スタイルは、ワープロ ドキュメント パッケージ内の専用パーツに格納されます。 Microsoft Word 2010ドキュメントには、1 つのスタイル パーツが含まれています。 以降のバージョンの Microsoft では、2 つ目のスタイルWithEffects パーツを追加Word。 Open XML SDK Productivity Tool for Microsoft Office のドキュメント エクスプローラーの次の図は、スタイルを含むサンプル Word 2013 以降のドキュメントのドキュメント パーツを示しています。
図 1. ワープロ ドキュメントのスタイル パーツ
Word 2013+ から Word 2010 までドキュメントを "ラウンドトリップ" するために、Word 2013+ は元のスタイル パーツと新しいスタイル パーツの両方を保持します。 (Office Open XML ファイル形式の仕様では、Microsoft Wordが認識しない部分を無視する必要があります。Word 2010 では、2013 以降でドキュメントに追加される stylesWithEffects 部分Word気付きません)。
このトピックのコード例を使用して、これらのスタイル パーツを置き換えることができます。
ReplaceStyles メソッド
ReplaceStyles
サンプル メソッドを使用して、ワープロドキュメントのスタイルを別のワープロドキュメントのスタイルに置き換えることができます。
ReplaceStyles
メソッドは、2 つのパラメーターを受け取ります。最初のパラメーターには、抽出するスタイルを含むファイルのパスを示す文字列が含まれています。 2 番目のパラメーターには、スタイルをコピーするファイルのパスを示す文字列が含まれており、実質的にスタイルを完全に置き換えます。
static void ReplaceStyles(string fromDoc, string toDoc)
ReplaceStyles
メソッドとそのサポート メソッドの完全なコード 一覧については、「サンプル コード」セクションを参照してください。
サンプル メソッドの呼び出し
サンプル メソッドを呼び出すには、1 つ目のパラメーターで、スタイルを抽出するファイルのパスを示す文字列を渡し、2 つ目のパラメーターで、スタイルを置き換えるファイルのパスを示す文字列を渡します。 次のサンプル コードは例を示しています。 コードの実行が完了すると、対象のドキュメントのスタイルが置き換えられ、その結果、そのドキュメントのテキストの表示形式には新しいスタイルが適用されます。
string fromDoc = args[0];
string toDoc = args[1];
ReplaceStyles(fromDoc, toDoc);
コードの動作のしくみ
このコードは、まずスタイル パーツ、次にスタイル stylesWithEffects パーツを抽出および置換し、2 つのサポート メソッドにより作業のほとんどを実行します。
ExtractStylesPart
メソッドには、スタイルまたは stylesWithEffects パーツのコンテンツを抽出し、それを XDocument オブジェクトに配置するジョブがあります。
ReplaceStylesPart
メソッドは、ExtractStylesPart
によって作成されたオブジェクトを受け取り、そのコンテンツを使用して、ターゲット ドキュメントのスタイルまたはスタイルWithEffects パーツを置き換えます。
// Extract and replace the styles part.
XDocument? node = ExtractStylesPart(fromDoc, false);
if (node is not null)
{
ReplaceStylesPart(toDoc, node, false);
}
ExtractStylesPart
または ReplaceStylesPart
メソッドのシグネチャの最後のパラメーターによって、スタイル パーツまたは stylesWithEffects パーツのどちらを使用するかが決まります。 styles パーツを抽出し、置き換える場合は、値を false に指定します。 stylesWithEffects パーツを抽出し、置き換える場合は、値を指定しない (パラメーターはオプションです) か、値を true (既定) に指定します。
// Extract and replace the stylesWithEffects part. To fully support
// round-tripping from Word 2010 to Word 2007, you should
// replace this part, as well.
node = ExtractStylesPart(fromDoc);
if (node is not null)
{
ReplaceStylesPart(toDoc, node);
}
return;
ExtractStylesPart
メソッドの詳細については、関連するサンプルを参照してください。 次のセクションでは、 ReplaceStylesPart
メソッドについて説明します。
ReplaceStylesPart メソッド
ReplaceStylesPart
メソッドを使用すると、ドキュメント内のスタイルまたは styleWithEffects パーツを置き換えることができます。Word 2010 または Word 2013 以降のドキュメントの同じパーツを含むXDocument
インスタンスを指定します (このトピックの前のサンプル コードに示すように、ExtractStylesPart
メソッドを使用してそのインスタンスを取得できます)。
ReplaceStylesPart
メソッドは、3 つのパラメーターを受け取ります。最初のパラメーターには、変更するファイルへのパスを示す文字列が含まれています。 2 番目のパラメーターには、別のワープロ ドキュメントのスタイルまたは stylesWithEffect パーツを含むXDocument
オブジェクトが含まれています。3 番目のパラメーターは、スタイル パーツと stylesWithEffects パーツのどちらを置き換えるかを示します (このトピックの前のサンプル コードに示すように、2013 以降のドキュメントではこのプロシージャを 2 Word 回呼び出し、各パーツをソース ドキュメントの対応する部分に置き換える必要があります)。
static void ReplaceStylesPart(string fileName, XDocument newStyles, bool setStylesWithEffectsPart = true)
ReplaceStylesPart コードの動作のしくみ
ReplaceStylesPart
メソッドは、指定したドキュメントを調べて、スタイルまたはスタイルWithEffects パーツを探します。
要求されたパーツが存在する場合、メソッドは指定された XDocument
を選択したパーツに保存します。
コードは、まず、 Open メソッドを使用してドキュメントを開き、ドキュメントを読み取り/書き込みアクセス用に開く必要があることを示します (最後の true
パラメーター)。 開いているドキュメントを指定すると、コードは MainDocumentPart プロパティを使用してメインドキュメント パーツに移動し、スタイル パーツへの参照を保持するために stylesPart
という名前の変数を準備します。
// Open the document for write access and get a reference.
using (var document = WordprocessingDocument.Open(fileName, true))
{
if (document.MainDocumentPart is null || (document.MainDocumentPart.StyleDefinitionsPart is null && document.MainDocumentPart.StylesWithEffectsPart is null))
{
throw new ArgumentNullException("MainDocumentPart and/or one or both of the Styles parts is null.");
}
// Get a reference to the main document part.
var docPart = document.MainDocumentPart;
// Assign a reference to the appropriate part to the
// stylesPart variable.
StylesPart? stylesPart = null;
適切なスタイル パーツを検索する
次のコードでは、 setStylesWithEffectsPart
Boolean パラメーターを使用して、要求されたスタイル パーツへの参照を取得します。 この値を基にして、要求されたスタイル パーツへの参照を取得し、 stylesPart
変数に格納します。
if (setStylesWithEffectsPart)
{
stylesPart = docPart.StylesWithEffectsPart;
}
else
{
stylesPart = docPart.StyleDefinitionsPart;
}
パーツのコンテンツを保存する
要求された部分が存在すると仮定すると、コードはメソッドに渡された XDocument
の内容全体をその部分に保存する必要があります。 各パーツには、Streamを返すGetStream() メソッドが用意されています。
コードは、Stream インスタンスを StreamWriter(Stream) クラスのコンストラクターに渡し、パーツのストリームの周りにストリーム ライターを作成します。 最後に、コードは XDocument の Save(Stream) メソッドを呼び出し、その内容をスタイル パーツに保存します。
// If the part exists, populate it with the new styles.
if (stylesPart is not null)
{
newStyles.Save(new StreamWriter(stylesPart.GetStream(FileMode.Create, FileAccess.Write)));
}
サンプル コード
C# と Visual Basic の完全な ReplaceStyles
、 ReplaceStylesPart
、 ExtractStylesPart
メソッドを次に示します。
// Replace the styles in the "to" document with the styles in
// the "from" document.
static void ReplaceStyles(string fromDoc, string toDoc)
{
// Extract and replace the styles part.
XDocument? node = ExtractStylesPart(fromDoc, false);
if (node is not null)
{
ReplaceStylesPart(toDoc, node, false);
}
// Extract and replace the stylesWithEffects part. To fully support
// round-tripping from Word 2010 to Word 2007, you should
// replace this part, as well.
node = ExtractStylesPart(fromDoc);
if (node is not null)
{
ReplaceStylesPart(toDoc, node);
}
return;
}
// Given a file and an XDocument instance that contains the content of
// a styles or stylesWithEffects part, replace the styles in the file
// with the styles in the XDocument.
static void ReplaceStylesPart(string fileName, XDocument newStyles, bool setStylesWithEffectsPart = true)
{
// Open the document for write access and get a reference.
using (var document = WordprocessingDocument.Open(fileName, true))
{
if (document.MainDocumentPart is null || (document.MainDocumentPart.StyleDefinitionsPart is null && document.MainDocumentPart.StylesWithEffectsPart is null))
{
throw new ArgumentNullException("MainDocumentPart and/or one or both of the Styles parts is null.");
}
// Get a reference to the main document part.
var docPart = document.MainDocumentPart;
// Assign a reference to the appropriate part to the
// stylesPart variable.
StylesPart? stylesPart = null;
if (setStylesWithEffectsPart)
{
stylesPart = docPart.StylesWithEffectsPart;
}
else
{
stylesPart = docPart.StyleDefinitionsPart;
}
// If the part exists, populate it with the new styles.
if (stylesPart is not null)
{
newStyles.Save(new StreamWriter(stylesPart.GetStream(FileMode.Create, FileAccess.Write)));
}
}
}
// Extract the styles or stylesWithEffects part from a
// word processing document as an XDocument instance.
static XDocument ExtractStylesPart(string fileName, bool getStylesWithEffectsPart = true)
{
// Declare a variable to hold the XDocument.
XDocument? styles = null;
// Open the document for read access and get a reference.
using (var document = WordprocessingDocument.Open(fileName, false))
{
// Get a reference to the main document part.
var docPart = document.MainDocumentPart;
if (docPart is null)
{
throw new ArgumentNullException("MainDocumentPart is null.");
}
// Assign a reference to the appropriate part to the
// stylesPart variable.
StylesPart stylesPart;
if (getStylesWithEffectsPart && docPart.StylesWithEffectsPart is not null)
{
stylesPart = docPart.StylesWithEffectsPart;
}
else if (docPart.StyleDefinitionsPart is not null)
{
stylesPart = docPart.StyleDefinitionsPart;
}
else
{
throw new ArgumentNullException("StyleWithEffectsPart and StyleDefinitionsPart are undefined");
}
using (var reader = XmlNodeReader.Create(stylesPart.GetStream(FileMode.Open, FileAccess.Read)))
{
// Create the XDocument.
styles = XDocument.Load(reader);
}
}
// Return the XDocument instance.
return styles;
}