段落を別のプレゼンテーションに移動する
このトピックでは、Open XML SDK for Office のクラスを使用して、あるプレゼンテーションから別のプレゼンテーションにプログラムで段落を移動する方法について説明します。
PresentationDocument オブジェクトを取得する
Open XML SDK では、 PresentationDocument クラスはプレゼンテーション ドキュメント パッケージを表します。 プレゼンテーション ドキュメントを操作するには、まず PresentationDocument
クラスのインスタンスを作成してから、そのインスタンスを操作します。 ドキュメントからクラス インスタンスを作成するには、ファイル パスを使用する Open メソッドを呼び出し、2 番目のパラメーターとしてブール値を使用してドキュメントを編集可能にするかどうかを指定します。 読み取り/書き込みのためにドキュメントを開くには、次のusing
ステートメントに示すように、このパラメーターの値true
を指定します。
このコードでは、 sourceFile
パラメーターは、ドキュメントを開くファイルのパスを表す文字列です。
v3.0.0 以降では、using ステートメントに依存することを優先して、Close() メソッドが削除されました。
これにより、閉じかっこに達したときに、 Dispose() メソッドが自動的に呼び出されます。
using
ステートメントに続くブロックは、using
ステートメントで作成または名前付けされたオブジェクトのスコープを確立します(この場合はsourceDoc
。
プレゼンテーション ドキュメントの基本構造
PresentationML
ドキュメントの基本的なドキュメント構造は、多数のパーツで構成され、その中にはプレゼンテーション定義を含むメインパーツがあります。
ISO/IEC 29500 仕様の次のテキストでは、PresentationML
パッケージの全体的な形式について説明します。
PresentationML
パッケージのメイン部分は、プレゼンテーション ルート要素で始まります。 この要素にはプレゼンテーションが含まれており、プレゼンテーションは スライド リスト、スライド マスター リスト、ノート マスター リスト、配布資料マスター リストを参照します。 スライド リストはプレゼンテーション内のすべてのスライドを参照します。スライド マスター リストはプレゼンテーションで使用されるスライド マスター全体を参照します。ノート マスターにはノート ページの書式設定に関する情報が含まれます。配布資料マスターは配布資料がどのように表示されるかを示します。配布資料とは、聴衆に提供できるように一連のスライドを印刷したものです。
テキストやグラフィックのように、各スライドにはコメントとノートを含めることができ、レイアウトを指定したり、1 つ以上のカスタム プレゼンテーションに組み込んだりできます。 コメントは、プレゼンテーション スライド デッキをメンテナンスする人向けの注釈です。 ノートは、プレゼンテーションの発表者または参加者向けのリマインダーやメモです。
PresentationML
ドキュメントには、アニメーション、オーディオ、ビデオ、スライド間の切り替えなどのその他の機能があります。
PresentationML
ドキュメントは、1 つのパーツに 1 つの大きな本文として格納されません。 その代わりに、特定のグループの機能を実現する要素が別個のパーツに格納されます。 たとえば、ドキュメント内のすべての作成者は 1 つの作成者パーツに格納され、各スライドには独自のパーツがあります。ISO/IEC 29500: 2016
次の XML コードの例は、267 と 256 という ID で示される 2 つのスライドを含むプレゼンテーションを表します。
<p:presentation xmlns:p="…" … >
<p:sldMasterIdLst>
<p:sldMasterId
xmlns:rel="https://…/relationships" rel:id="rId1"/>
</p:sldMasterIdLst>
<p:notesMasterIdLst>
<p:notesMasterId
xmlns:rel="https://…/relationships" rel:id="rId4"/>
</p:notesMasterIdLst>
<p:handoutMasterIdLst>
<p:handoutMasterId
xmlns:rel="https://…/relationships" rel:id="rId5"/>
</p:handoutMasterIdLst>
<p:sldIdLst>
<p:sldId id="267"
xmlns:rel="https://…/relationships" rel:id="rId2"/>
<p:sldId id="256"
xmlns:rel="https://…/relationships" rel:id="rId3"/>
</p:sldIdLst>
<p:sldSz cx="9144000" cy="6858000"/>
<p:notesSz cx="6858000" cy="9144000"/>
</p:presentation>
Open XML SDK を使用すると、PresentationML 要素に対応する厳密に型指定されたクラスを使用して、ドキュメント構造とコンテンツを作成できます。 これらのクラスは、 名前空間にあります。 次の表に、 sld
、 sldLayout
、 sldMaster
、および notesMaster
の各要素に対応するクラスのクラス名を示します。
PresentationML 要素 | Open XML SDK クラス | 説明 |
---|---|---|
<sld/> |
Slide | プレゼンテーション スライド。 SlidePart のルート要素 |
<sldLayout/> |
SlideLayout | スライド レイアウト。 SlideLayoutPart のルート要素 |
<sldMaster/> |
SlideMaster | スライド マスター。 SlideMasterPart のルート要素 |
<notesMaster/> |
NotesMaster | ノート マスター (または handoutMaster)。 NotesMasterPart のルート要素 |
図形テキスト本体の構造
ISO/IEC 29500 仕様で、この要素の構造は次のように記述されています。
この要素は、対応する図形の内側に含めるテキストが存在することを指定するものです。 目に見えるすべてのテキストと、目に見えるすべてのテキスト関連プロパティがこの要素に含まれます。 複数の段落と、段落内に複数のテキスト セクションを含めることもできます。
© ISO/IEC 29500: 2016
次の表に、図形テキスト本体の子要素と、各子要素の説明を示します。
子の要素 | 説明 |
---|---|
bodyPr | 本体のプロパティ |
lstStyle | テキスト リストのプロパティ |
p | テキスト段落 |
次の XML スキーマ フラグメントが、この要素のコンテンツを定義します。
<complexType name="CT_TextBody">
<sequence>
<element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/>
<element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/>
<element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/>
</sequence>
</complexType>
サンプル コードの動作のしくみ
このトピックのコードは、 MoveParagraphToPresentation
と GetFirstSlide
の 2 つのメソッドで構成されています。 最初のメソッドは、2 つの文字列パラメーターを受け取ります。1 つは、移動する段落を含むソース ファイルを表すパラメーターと、段落の移動先のターゲット ファイルを表すパラメーターです。 メソッドは両方のプレゼンテーション ファイルを開き、 GetFirstSlide
メソッドを呼び出して各ファイルの最初のスライドを取得します。 次に、各スライドの最初の TextBody
図形とソース図形の最初の段落を取得します。 ソース段落の deep clone
を実行し、ソース Paragraph
オブジェクト自体だけでなく、そのオブジェクトに含まれるすべてのテキストもコピーします。 次に、複製した段落をターゲット ファイルに挿入し、ソース ファイルからソース 段落を削除し、プレースホルダー 段落に置き換えます。 最後に、変更したスライドを両方のプレゼンテーションに保存します。
// Moves a paragraph range in a TextBody shape in the source document
// to another TextBody shape in the target document.
static void MoveParagraphToPresentation(string sourceFile, string targetFile)
{
// Open the source file as read/write.
using (PresentationDocument sourceDoc = PresentationDocument.Open(sourceFile, true))
// </Snippet1
// Open the target file as read/write.
using (PresentationDocument targetDoc = PresentationDocument.Open(targetFile, true))
{
// Get the first slide in the source presentation.
SlidePart slide1 = GetFirstSlide(sourceDoc);
// Get the first TextBody shape in it.
TextBody textBody1 = slide1.Slide.Descendants<TextBody>().First();
// Get the first paragraph in the TextBody shape.
// Note: "Drawing" is the alias of namespace DocumentFormat.OpenXml.Drawing
Drawing.Paragraph p1 = textBody1.Elements<Drawing.Paragraph>().First();
// Get the first slide in the target presentation.
SlidePart slide2 = GetFirstSlide(targetDoc);
// Get the first TextBody shape in it.
TextBody textBody2 = slide2.Slide.Descendants<TextBody>().First();
// Clone the source paragraph and insert the cloned. paragraph into the target TextBody shape.
// Passing "true" creates a deep clone, which creates a copy of the
// Paragraph object and everything directly or indirectly referenced by that object.
textBody2.Append(p1.CloneNode(true));
// Remove the source paragraph from the source file.
textBody1.RemoveChild(p1);
// Replace the removed paragraph with a placeholder.
textBody1.AppendChild(new Drawing.Paragraph());
}
}
GetFirstSlide
メソッドは、渡されたPresentationDocument
オブジェクトを取得し、そのプレゼンテーション パーツを取得し、スライド リストの最初のスライドの ID を取得します。 その後、スライドのリレーションシップ ID を取得し、リレーションシップ ID からスライド パーツを取得して、呼び出し元のメソッドにスライド パーツを返します。
// Get the slide part of the first slide in the presentation document.
static SlidePart GetFirstSlide(PresentationDocument presentationDocument)
{
// Get relationship ID of the first slide
PresentationPart part = presentationDocument.PresentationPart ?? presentationDocument.AddPresentationPart();
SlideIdList slideIdList = part.Presentation.SlideIdList ?? part.Presentation.AppendChild(new SlideIdList());
SlideId slideId = part.Presentation.SlideIdList?.GetFirstChild<SlideId>() ?? slideIdList.AppendChild<SlideId>(new SlideId());
string? relId = slideId.RelationshipId;
if (relId is null)
{
throw new ArgumentNullException(nameof(relId));
}
// Get the slide part by the relationship ID.
SlidePart slidePart = (SlidePart)part.GetPartById(relId);
return slidePart;
}
サンプル コード
以下に、C# と Visual Basic による完全なサンプル コードを示します。
// Moves a paragraph range in a TextBody shape in the source document
// to another TextBody shape in the target document.
static void MoveParagraphToPresentation(string sourceFile, string targetFile)
{
// Open the source file as read/write.
using (PresentationDocument sourceDoc = PresentationDocument.Open(sourceFile, true))
// </Snippet1
// Open the target file as read/write.
using (PresentationDocument targetDoc = PresentationDocument.Open(targetFile, true))
{
// Get the first slide in the source presentation.
SlidePart slide1 = GetFirstSlide(sourceDoc);
// Get the first TextBody shape in it.
TextBody textBody1 = slide1.Slide.Descendants<TextBody>().First();
// Get the first paragraph in the TextBody shape.
// Note: "Drawing" is the alias of namespace DocumentFormat.OpenXml.Drawing
Drawing.Paragraph p1 = textBody1.Elements<Drawing.Paragraph>().First();
// Get the first slide in the target presentation.
SlidePart slide2 = GetFirstSlide(targetDoc);
// Get the first TextBody shape in it.
TextBody textBody2 = slide2.Slide.Descendants<TextBody>().First();
// Clone the source paragraph and insert the cloned. paragraph into the target TextBody shape.
// Passing "true" creates a deep clone, which creates a copy of the
// Paragraph object and everything directly or indirectly referenced by that object.
textBody2.Append(p1.CloneNode(true));
// Remove the source paragraph from the source file.
textBody1.RemoveChild(p1);
// Replace the removed paragraph with a placeholder.
textBody1.AppendChild(new Drawing.Paragraph());
}
}
// Get the slide part of the first slide in the presentation document.
static SlidePart GetFirstSlide(PresentationDocument presentationDocument)
{
// Get relationship ID of the first slide
PresentationPart part = presentationDocument.PresentationPart ?? presentationDocument.AddPresentationPart();
SlideIdList slideIdList = part.Presentation.SlideIdList ?? part.Presentation.AppendChild(new SlideIdList());
SlideId slideId = part.Presentation.SlideIdList?.GetFirstChild<SlideId>() ?? slideIdList.AppendChild<SlideId>(new SlideId());
string? relId = slideId.RelationshipId;
if (relId is null)
{
throw new ArgumentNullException(nameof(relId));
}
// Get the slide part by the relationship ID.
SlidePart slidePart = (SlidePart)part.GetPartById(relId);
return slidePart;
}