ワープロ ドキュメント内の段落にスタイルを適用する
このトピックでは、Open XML SDK for Office のクラスを使用して、プログラムによってワープロ ドキュメント内の段落にスタイルを適用する方法について説明します。 このタスクを示ApplyStyleToParagraph
メソッドの例と、スタイルが存在するかどうかをチェックし、新しいスタイルを追加し、スタイル パーツを追加するためのいくつかの補助的な例メソッドが含まれています。
ApplyStyleToParagraph メソッド
ApplyStyleToParagraph
例のメソッドを使用して、段落にスタイルを適用できます。 最初に、文書への参照と、スタイルを設定する段落への参照を取得する必要があります。 メソッドは、開くワープロ文書へのパス、適用するスタイルの styleid、適用するスタイルの名前、およびスタイルを適用する段落への参照を示す 4 つのパラメーターを受け入れます。
static void ApplyStyleToParagraph(WordprocessingDocument doc, string styleid, string stylename, Paragraph p)
このトピックのこれ以降のセクションでは、このメソッドおよびそれをサポートするコードの実装と、それを呼び出す方法について説明します。 完全なサンプル コードについては、このトピックの末尾の「サンプル コード」セクションを参照してください。
WordprocessingDocument オブジェクトを取得する
「サンプル コード」セクションでは、サンプルのメソッドを呼び出すためにセットアップする必要があるコードも示します。 このメソッドを使用してドキュメント内の段落にスタイルを適用するには、まず、開いているドキュメントへの参照が必要です。 Open XML SDK では、WordprocessingDocument クラスはWord ドキュメント パッケージを表します。 Word ドキュメントを開いて操作するには、ドキュメントから WordprocessingDocument クラスのインスタンスを作成します。 インスタンスを作成した後、それを使用して、ドキュメントのテキストを含むメインドキュメント パーツへのアクセス権を取得します。 メイン ドキュメント パーツのコンテンツは、パッケージ内で WordprocessingML マークアップを使用して XML として表されます。
クラス インスタンスを作成するには、 Open メソッドのいずれかのオーバーロードを呼び出します。 次のサンプル コードは、 DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open(String, Boolean)
オーバーロードを使用する方法を示しています。 最初のパラメーターは、開くドキュメントへの完全なパスを表す文字列を受け取ります。 2 番目のパラメーターは、 true
または false
の値を受け取り、編集のためにファイルを開くかどうかを表します。 この例では、ファイルへの読み取り/書き込みアクセスを有効にするパラメーターが true
されています。
using (WordprocessingDocument doc = WordprocessingDocument.Open(args[0], true))
WordProcessingML ドキュメントの構造
WordProcessingML
ドキュメントの基本的なドキュメント構造は、document
要素とbody
要素で構成され、その後に段落を表す p
などの 1 つ以上のブロック レベル要素が続きます。 段落には、1 つ以上の r
要素が含まれています。
r
は、書式設定などのプロパティの共通セットを持つテキストの領域である run を表します。 実行には、1 つ以上の t
要素が含まれています。
t
要素には、テキストの範囲が含まれています。 次のコード例は、"テキストの例" というテキストを含むドキュメントの WordprocessingML
マークアップを示しています。
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:t>Example text.</w:t>
</w:r>
</w:p>
</w:body>
</w:document>
Open XML SDK を使用すると、 WordprocessingML
要素に対応する厳密に型指定されたクラスを使用して、ドキュメント構造とコンテンツを作成できます。 これらのクラスは、 名前空間にあります。 次の表に、 document
、 body
、 p
、 r
、 t
の各要素に対応するクラスのクラス名を示します。
WordprocessingML 要素 | Open XML SDK クラス | 説明 |
---|---|---|
<document/> |
Document | メイン ドキュメント パーツのルート要素。 |
<body/> |
Body | ISO/IEC 29500 仕様で指定されている、段落、表、注釈などのブロック レベル構造のコンテナー |
<p/> |
Paragraph | 段落 |
<r/> |
Run | セクション |
<t/> |
Text | さまざまなテキスト |
WordprocessingML ドキュメントのパーツと要素の全体的な構造の詳細については、「 WordprocessingML ドキュメントの構造」を参照してください。
段落のスタイルを取得する
サンプル コードは、ファイルを開いた後、最初の段落への参照を取得します。 一般的なワープロドキュメント本文には多くの種類の要素が含まれているため、コードはドキュメントの本文の子孫を Paragraph
型の子孫にフィルター処理します。 その後、 ElementAtOrDefault メソッドを使用して、段落への参照を取得します。 要素にはゼロから始まるインデックスが付けられているので、次のコードの例に示すように、最初の段落への参照を取得するにはゼロを渡します。
// Get the first paragraph in the document.
Paragraph? paragraph = doc?.MainDocumentPart?.Document?.Body?.Descendants<Paragraph>().ElementAtOrDefault(0);
見つかった段落への参照は、paragraph という名前の変数に格納されます。 指定したインデックスに段落が見つからない場合、 ElementAtOrDefault
メソッドは既定値として null を返します。 これにより、null に関するテストを実行し、該当するエラー メッセージを伴うエラーをスローする機会が得られます。
ドキュメントと段落への参照を取得したら、 ApplyStyleToParagraph
例メソッドを呼び出して残りの作業を行うことができます。 このメソッドを呼び出すには、1 つ目のパラメーターとしてドキュメントへの参照を、2 つ目のパラメーターとして適用するスタイルの styleid を、3 つ目のパラメーターとしてスタイルの名前を、4 つ目のパラメーターとしてスタイルを適用する段落への参照を渡します。
段落プロパティ要素を追加する
このサンプル メソッドの最初の手順として、段落に段落プロパティ要素があることを確認します。 段落プロパティ要素は、段落の子要素であり、段落の書式を指定できる一連のプロパティが含まれます。
ISO/IEC 29500 仕様の次の情報では、段落の書式設定を指定するために使用される pPr
(段落プロパティ) 要素について説明します。 先頭に § が付いている項番号は、ISO 仕様での番号です。
段落内では、段落レベルのすべてのリッチ書式設定が pPr
要素 (§17.3.1.25;§17.3.1.26) 内に格納されます。 [注記: 段落プロパティの例として、配置、罫線、ハイフネーションの無効化、インデント、行間、網かけ、テキストの方向、段落内での改ページ処理などがあります。
プロパティの中には、段落に適用するスタイルを指定する pStyle
要素があります。 たとえば、次のサンプルのマークアップに、"OverdueAmount" スタイルを指定した pStyle 要素が示されています。
<w:p xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:pPr>
<w:pStyle w:val="OverdueAmount" />
</w:pPr>
...
</w:p>
Open XML SDK では、 pPr
要素は ParagraphProperties クラスによって表されます。 このコードでは、 要素が存在するかどうかを決定し、存在しない場合は ParagraphProperties
クラスの新しいインスタンスを作成します。
pPr
要素は、p
(paragraph) 要素の子です。そのため、次のコード例に示すように、PrependChild メソッドを使用してインスタンスを追加します。
// If the paragraph has no ParagraphProperties object, create one.
if (p.Elements<ParagraphProperties>().Count() == 0)
{
p.PrependChild<ParagraphProperties>(new ParagraphProperties());
}
// Get the paragraph properties element of the paragraph.
ParagraphProperties pPr = p.Elements<ParagraphProperties>().First();
スタイル パーツを追加する
段落が見つかり、paragraph properties 要素が存在する状態で、スタイルを適用するための前提条件が整っていることを確認します。 WordprocessingML のスタイルは、独自の一意の部分に格納されます。 通常、Microsoft Word などのアプリケーションを使用してドキュメントを作成すると、パーツと基本スタイルのセットが自動的に作成されますが、ドキュメントが有効と見なされるためにスタイル パーツは必要ありません。 Open XML SDK を使用してプログラムでドキュメントを作成した場合、スタイル パーツは自動的に作成されません。明示的に作成する必要があります。 したがって、次のコードでは、スタイル パーツが存在することを確認し、存在しない場合は作成します。
// Get the Styles part for this document.
StyleDefinitionsPart? part = doc.MainDocumentPart?.StyleDefinitionsPart;
// If the Styles part does not exist, add it and then add the style.
if (part is null)
{
part = AddStylesPartToPackage(doc);
AddStylesPartToPackage
例メソッドは、スタイル パーツを追加する処理を行います。
StyleDefinitionsPart
型の一部を作成し、メイン ドキュメント パーツに子として追加します。 その後、コードは、すべてのスタイルを含む親要素である Styles
ルート要素を追加します。
Styles
要素は、Open XML SDK の Styles クラスによって表されます。 最後に、コードはこのパーツを保存します。
// Add a StylesDefinitionsPart to the document. Returns a reference to it.
static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument doc)
{
MainDocumentPart mainDocumentPart = doc.MainDocumentPart ?? doc.AddMainDocumentPart();
StyleDefinitionsPart part = mainDocumentPart.AddNewPart<StyleDefinitionsPart>();
Styles root = new Styles();
return part;
}
スタイルが存在することを確認する
段落に存在しないスタイルを適用しても効果はありません。例外は生成されません。書式設定の変更は発生しません。 コード例では、スタイルを適用する前にスタイルが存在することを確認します。 スタイルはスタイル パーツに格納されるため、スタイル パーツが存在しない場合、スタイル自体は存在できません。
スタイル パーツが存在する場合、コードは、 IsStyleIdInDocument
のサンプル メソッドを呼び出し、ドキュメントと styleid を渡すことによって、一致するスタイルを検証します。 styleid に一致するものが見つからない場合、コードは、 GetStyleIdFromStyleName
サンプル メソッドを呼び出してスタイル名を渡すことで styleid を検索しようとします。
スタイルパーツが存在しなかったか、スタイルパーツが存在するがスタイルが存在しない場合、コードは AddNewStyle
サンプルメソッドを呼び出してスタイルを追加します。
// Get the Styles part for this document.
StyleDefinitionsPart? part = doc.MainDocumentPart?.StyleDefinitionsPart;
// If the Styles part does not exist, add it and then add the style.
if (part is null)
{
part = AddStylesPartToPackage(doc);
AddNewStyle(part, styleid, stylename);
}
else
{
// If the style is not in the document, add it.
if (IsStyleIdInDocument(doc, styleid) != true)
{
// No match on styleid, so let's try style name.
string? styleidFromName = GetStyleIdFromStyleName(doc, stylename);
if (styleidFromName is null)
{
AddNewStyle(part, styleid, stylename);
}
else
styleid = styleidFromName;
}
}
IsStyleInDocument
のサンプル メソッド内では、作業は、メイン ドキュメント パーツのStyleDefinitionsPartのStyles
プロパティを使用してStyles
要素を取得し、その要素の子としてスタイルが存在するかどうかを判断する作業から始まります。 すべてのスタイル要素は、styles 要素の子として格納されます。
スタイルが存在する場合は、このコードは styleid が一致するものを探します。 styleid は、ドキュメント内の多くの箇所でスタイルを参照するために使用される、スタイルの属性であり、主識別子と考えることができます。 一般に、styleid は、コード内でスタイルを識別するために使用します。 一致するものが見つからない場合、 FirstOrDefault メソッドの既定値は null であるため、次の抜粋に示すように、コードは null を確認してスタイルが一致したかどうかを確認します。
// Return true if the style id is in the document, false otherwise.
static bool IsStyleIdInDocument(WordprocessingDocument doc, string styleid)
{
// Get access to the Styles element for this document.
Styles? s = doc.MainDocumentPart?.StyleDefinitionsPart?.Styles;
if (s is null)
{
return false;
}
// Check that there are styles and how many.
int n = s.Elements<Style>().Count();
if (n == 0)
{
return false;
}
// Look for a match on styleid.
Style? style = s.Elements<Style>()
.Where(st => (st.StyleId is not null && st.StyleId == styleid) && (st.Type is not null && st.Type == StyleValues.Paragraph))
.FirstOrDefault();
if (style is null)
{
return false;
}
return true;
}
styleid に基づいてスタイルが見つからない場合、コードはスタイル名に基づいて一致を検索しようとします。
GetStyleIdFromStyleName
例のメソッドでは、スタイル名で一致するものを探し、見つかった場合は一致する要素の styleid を返し、見つからない場合は null を返します。
スタイルパーツにスタイルを追加する
AddNewStyle
例のメソッドは、3 つのパラメーターを受け取ります。 最初のパラメーターは、スタイル パーツへの参照を受け取ります。
2 番目のパラメーターはスタイルの styleid を受け取り、3 番目のパラメーターはスタイル名を受け取ります。
AddNewStyle
コードは、指定したパーツ内に名前付きスタイル定義を作成します。
スタイルを作成するために、コードは Style クラスをインスタンス化し、スタイル (段落) の Type や StyleIdなどの特定のプロパティを設定します。 前述したように、styleid はスタイルを参照するためにドキュメントで使用されるので、その主識別子と考えることができます。 一般的に、styleid は、コード内でスタイルを識別するために使用します。 スタイルには、ユーザー インターフェイスに表示するための分かりやすいスタイル名を別に付けることができます。 このため、スタイル名は、Heading 1 のように大文字小文字と空白を適切に使用して表されることが多いのに対し、styleid は内部使用を意図しているので、heading1 のように、より簡潔に表されます。 次のサンプル コードでは、styleid とスタイル名については、styleid パラメーターと stylename パラメーターからそれぞれの値を取得します。
その次の手順として、新しいスタイルの基になるスタイル、次の段落に自動的に適用するスタイルなど、いくつかの追加のプロパティを指定します。 このコードでは、この両方を "標準" スタイルとして指定します。 ここで指定する値は、標準スタイルの styleid であることに注意してください。 このコードでは、これらのプロパティを style 要素の子として追加します。
コードがスタイルのインスタンス化および基本プロパティのセットアップを完了したら、スタイルの書式設定を操作します。 スタイルの書式設定は、段落プロパティ (pPr
) および実行プロパティ (rPr
) 要素で実行されます。 段落内のセクションに対してフォントと色の特性を設定するには、セクション プロパティを使用します。
適切な子要素を持つ rPr
要素を作成するために、コードは StyleRunProperties クラスのインスタンスを作成し、適切なプロパティ クラスのインスタンスを追加します。 このサンプル コードでは、スタイルに Lucida Console フォント、フォント サイズ 12 を使用し、太字と斜体を適用して、ドキュメント テーマ パーツに指定されているアクセント 2 の色を使用します。 フォント サイズは 0.5 ポイント単位で指定されるので、値を 24 にすると 12 ポイントになります。
スタイル定義が完了すると、次のコード例に示すように、このコードはスタイル パーツの styles 要素にこのスタイルを追加します。
// Create a new style with the specified styleid and stylename and add it to the specified
// style definitions part.
static void AddNewStyle(StyleDefinitionsPart styleDefinitionsPart, string styleid, string stylename)
{
// Get access to the root element of the styles part.
styleDefinitionsPart.Styles ??= new Styles();
Styles styles = styleDefinitionsPart.Styles;
// Create a new paragraph style and specify some of the properties.
Style style = new Style()
{
Type = StyleValues.Paragraph,
StyleId = styleid,
CustomStyle = true
};
StyleName styleName1 = new StyleName() { Val = stylename };
BasedOn basedOn1 = new BasedOn() { Val = "Normal" };
NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "Normal" };
style.Append(styleName1);
style.Append(basedOn1);
style.Append(nextParagraphStyle1);
// Create the StyleRunProperties object and specify some of the run properties.
StyleRunProperties styleRunProperties1 = new StyleRunProperties();
Bold bold1 = new Bold();
Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 };
RunFonts font1 = new RunFonts() { Ascii = "Lucida Console" };
Italic italic1 = new Italic();
// Specify a 12 point size.
FontSize fontSize1 = new FontSize() { Val = "24" };
styleRunProperties1.Append(bold1);
styleRunProperties1.Append(color1);
styleRunProperties1.Append(font1);
styleRunProperties1.Append(fontSize1);
styleRunProperties1.Append(italic1);
// Add the run properties to the style.
style.Append(styleRunProperties1);
// Add the style to the styles part.
styles.Append(style);
}
サンプル コード
以下に、C# と Visual Basic の両方の完全なサンプル コードを示します。
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Linq;
using (WordprocessingDocument doc = WordprocessingDocument.Open(args[0], true))
{
// Get the first paragraph in the document.
Paragraph? paragraph = doc?.MainDocumentPart?.Document?.Body?.Descendants<Paragraph>().ElementAtOrDefault(0);
if (paragraph is not null)
{
ApplyStyleToParagraph(doc!, "MyStyle", "MyStyleName", paragraph);
}
}
// Apply a style to a paragraph.
static void ApplyStyleToParagraph(WordprocessingDocument doc, string styleid, string stylename, Paragraph p)
{
if (doc is null)
{
throw new ArgumentNullException(nameof(doc));
}
// If the paragraph has no ParagraphProperties object, create one.
if (p.Elements<ParagraphProperties>().Count() == 0)
{
p.PrependChild<ParagraphProperties>(new ParagraphProperties());
}
// Get the paragraph properties element of the paragraph.
ParagraphProperties pPr = p.Elements<ParagraphProperties>().First();
// Get the Styles part for this document.
StyleDefinitionsPart? part = doc.MainDocumentPart?.StyleDefinitionsPart;
// If the Styles part does not exist, add it and then add the style.
if (part is null)
{
part = AddStylesPartToPackage(doc);
AddNewStyle(part, styleid, stylename);
}
else
{
// If the style is not in the document, add it.
if (IsStyleIdInDocument(doc, styleid) != true)
{
// No match on styleid, so let's try style name.
string? styleidFromName = GetStyleIdFromStyleName(doc, stylename);
if (styleidFromName is null)
{
AddNewStyle(part, styleid, stylename);
}
else
styleid = styleidFromName;
}
}
// Set the style of the paragraph.
pPr.ParagraphStyleId = new ParagraphStyleId() { Val = styleid };
}
// Return true if the style id is in the document, false otherwise.
static bool IsStyleIdInDocument(WordprocessingDocument doc, string styleid)
{
// Get access to the Styles element for this document.
Styles? s = doc.MainDocumentPart?.StyleDefinitionsPart?.Styles;
if (s is null)
{
return false;
}
// Check that there are styles and how many.
int n = s.Elements<Style>().Count();
if (n == 0)
{
return false;
}
// Look for a match on styleid.
Style? style = s.Elements<Style>()
.Where(st => (st.StyleId is not null && st.StyleId == styleid) && (st.Type is not null && st.Type == StyleValues.Paragraph))
.FirstOrDefault();
if (style is null)
{
return false;
}
return true;
}
// Return styleid that matches the styleName, or null when there's no match.
static string? GetStyleIdFromStyleName(WordprocessingDocument doc, string styleName)
{
StyleDefinitionsPart? stylePart = doc.MainDocumentPart?.StyleDefinitionsPart;
string? styleId = stylePart?.Styles?.Descendants<StyleName>()
.Where(s =>
{
OpenXmlElement? p = s.Parent;
EnumValue<StyleValues>? styleValue = p is null ? null : ((Style)p).Type;
return s.Val is not null && s.Val.Value is not null && s.Val.Value.Equals(styleName) &&
(styleValue is not null && styleValue == StyleValues.Paragraph);
})
.Select(n =>
{
OpenXmlElement? p = n.Parent;
return p is null ? null : ((Style)p).StyleId;
}).FirstOrDefault();
return styleId;
}
// Create a new style with the specified styleid and stylename and add it to the specified
// style definitions part.
static void AddNewStyle(StyleDefinitionsPart styleDefinitionsPart, string styleid, string stylename)
{
// Get access to the root element of the styles part.
styleDefinitionsPart.Styles ??= new Styles();
Styles styles = styleDefinitionsPart.Styles;
// Create a new paragraph style and specify some of the properties.
Style style = new Style()
{
Type = StyleValues.Paragraph,
StyleId = styleid,
CustomStyle = true
};
StyleName styleName1 = new StyleName() { Val = stylename };
BasedOn basedOn1 = new BasedOn() { Val = "Normal" };
NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "Normal" };
style.Append(styleName1);
style.Append(basedOn1);
style.Append(nextParagraphStyle1);
// Create the StyleRunProperties object and specify some of the run properties.
StyleRunProperties styleRunProperties1 = new StyleRunProperties();
Bold bold1 = new Bold();
Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 };
RunFonts font1 = new RunFonts() { Ascii = "Lucida Console" };
Italic italic1 = new Italic();
// Specify a 12 point size.
FontSize fontSize1 = new FontSize() { Val = "24" };
styleRunProperties1.Append(bold1);
styleRunProperties1.Append(color1);
styleRunProperties1.Append(font1);
styleRunProperties1.Append(fontSize1);
styleRunProperties1.Append(italic1);
// Add the run properties to the style.
style.Append(styleRunProperties1);
// Add the style to the styles part.
styles.Append(style);
}
// Add a StylesDefinitionsPart to the document. Returns a reference to it.
static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument doc)
{
MainDocumentPart mainDocumentPart = doc.MainDocumentPart ?? doc.AddMainDocumentPart();
StyleDefinitionsPart part = mainDocumentPart.AddNewPart<StyleDefinitionsPart>();
Styles root = new Styles();
return part;
}