如何:将一个演示文稿中的段落移到另一个演示文稿中

上次修改时间: 2010年10月14日

适用范围: Excel 2010 | Office 2010 | PowerPoint 2010 | Word 2010

本文内容
获取 PresentationDocument 对象
基本演示文稿文档结构
形状文本正文的结构
示例代码的工作方式
示例代码

本主题演示如何使用 Open XML SDK 2.0 for Microsoft Office 中的类以编程方式将一个演示文稿中的段落移动到另一个演示文稿中。

编译本主题中的代码需要使用以下程序集指令。

using System.Linq;
using DocumentFormat.OpenXml.Presentation;
using DocumentFormat.OpenXml.Packaging;
using Drawing = DocumentFormat.OpenXml.Drawing;
Imports System.Linq
Imports DocumentFormat.OpenXml.Presentation
Imports DocumentFormat.OpenXml.Packaging
Imports Drawing = DocumentFormat.OpenXml.Drawing

获取 PresentationDocument 对象

在 Open XML SDK 中,PresentationDocument 类表示演示文稿文档包。若要处理演示文稿文档,请首先创建 PresentationDocument 类的实例,然后处理该实例。若要从文档中创建类实例,请调用使用文件路径的 Open(String, Boolean) 方法,并以布尔值作为第二个参数来指定文档是否可编辑。若要打开文档进行读/写,请为此参数指定值 true,如以下的 using 语句所示。在该代码中,file 参数是一个字符串,表示要从中打开该文档的文件的路径。

using (PresentationDocument doc = PresentationDocument.Open(file, true))
{
    // Insert other code here.
}
Using doc As PresentationDocument = PresentationDocument.Open(file, True)
    ' Insert other code here.
End Using

using 语句提供典型 .Open, .Save, .Close 序列的建议备选序列。它确保在遇到右大括号时会自动调用 Dispose 方法(Open XML SDK 用来清理资源的内部方法)。using 语句后面的块为 using 语句中创建或指定的对象设定范围,在此示例中这个范围就是 doc

基本演示文稿文档结构

PresentationML 文档的基本文档结构包含大量部件,在这些部件中,主部件是包含演示文稿定义的部件。ISO/IEC 29500(该链接可能指向英文页面) 规范中的以下文本介绍了 PresentationML 包的整体形式。

PresentationML 包的主部件以演示文稿根元素开头。该元素包含演示文稿,演示文稿又引用幻灯片 列表、幻灯片母版 列表、备注母版 列表和讲义母版 列表。幻灯片列表指的是演示文稿中的所有幻灯片;幻灯片母版列表指的是演示文稿中使用的全部幻灯片母版;备注母版包含有关备注页格式的信息;讲义母版描述讲义的外观。

讲义 是打印的一组幻灯片,可提供给访问群体 以供他们将来参考。

除了文本和图形,每个幻灯片还可以包含注释 和备注,可以具有布局,并且可以是一个或多个自定义演示文稿 的组成部分。(注释是供维护演示文稿幻灯片平台的人员参考的批注。备注是供演示者或访问群体参考的提醒信息或一段文字。)

PresentationML 文档可以包含的其他功能如下:动画、音频、视频 以及幻灯片之间的切换。

PresentationML 文档不会存储为单个部件中的一个大型正文。而实现某些功能组合的元素会存储在各个部件中。例如,文档中的所有注释都存储在一个注释部件中,而每个幻灯片都有自己的部件。

© ISO/IEC29500: 2008。

以下 XML 代码段代表包含用 ID 267 和 256 表示的两个幻灯片的演示文稿。

<p:presentation xmlns:p="…" … > 
   <p:sldMasterIdLst>
      <p:sldMasterId
         xmlns:rel="http://…/relationships" rel:id="rId1"/>
   </p:sldMasterIdLst>
   <p:notesMasterIdLst>
      <p:notesMasterId
         xmlns:rel="http://…/relationships" rel:id="rId4"/>
   </p:notesMasterIdLst>
   <p:handoutMasterIdLst>
      <p:handoutMasterId
         xmlns:rel="http://…/relationships" rel:id="rId5"/>
   </p:handoutMasterIdLst>
   <p:sldIdLst>
      <p:sldId id="267"
         xmlns:rel="http://…/relationships" rel:id="rId2"/>
      <p:sldId id="256"
         xmlns:rel="http://…/relationships" rel:id="rId3"/>
   </p:sldIdLst>
       <p:sldSz cx="9144000" cy="6858000"/>
   <p:notesSz cx="6858000" cy="9144000"/>
</p:presentation>

通过使用 Open XML SDK 2.0,您可以利用 PresentationML 元素所对应的强类型类创建文档结构和内容。可以在 DocumentFormat.OpenXml.Presentation 命名空间中找到这些类。下表列出了 sld、sldLayout、sldMaster 和 notesMaster 元素所对应类的类名称。

PresentationML 元素

Open XML SDK 2.0 类

说明

sld

Slide

演示文稿幻灯片。它是 SlidePart 的根元素。

sldLayout

SlideLayout

幻灯片版式。它是 SlideLayoutPart 的根元素。

sldMaster

SlideMaster

幻灯片母版。它是 SlideMasterPart 的根元素。

notesMaster

NotesMaster

备注母版(或讲义母版)。它是 NotesMasterPart 的根元素。

形状文本正文的结构

ISO/IEC 29500(该链接可能指向英文页面) 规范中的以下信息介绍了此元素的结构。

此元素指定要在对应形状中包含的文本是否存在。此元素中包含所有可见文本和与可见文本相关的属性。可以存在多个段落,段落中可以存在多段连续文本。

© ISO/IEC29500: 2008。

下表列出了形状文本正文的子元素以及每个元素的说明。

子元素

说明

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。第一个方法采用两个字符串参数:一个表示包含要移动的段落的源文件;另一个表示要将段落移动到的目标文件。该方法打开两个演示文稿文件,再调用 GetFirstSlide 方法以获取每个文件中的第一张幻灯片。然后,该方法获取每张幻灯片中的第一个 TextBody 形状和源形状中的第一个段落。它对源段落执行深度克隆,即不仅复制源 Paragraph 对象本身,还复制该对象包含的一切内容,包括文本在内。然后在目标文件中插入克隆的段落,并从源文件中删除源段落,用占位符段落代替。最后,保存两个演示文稿中修改的幻灯片。

// Moves a paragraph range in a TextBody shape in the source document
// to another TextBody shape in the target document.
public static void MoveParagraphToPresentation(string sourceFile, string targetFile)
{
    // Open the source file as read/write.
    using (PresentationDocument sourceDoc = PresentationDocument.Open(sourceFile, true))
    {
        // 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<Drawing.Paragraph>(p1);

            // Replace the removed paragraph with a placeholder.
            textBody1.AppendChild<Drawing.Paragraph>(new Drawing.Paragraph());

            // Save the slide in the source file.
            slide1.Slide.Save();

            // Save the slide in the target file.
            slide2.Slide.Save();
        }
    }
}
' Moves a paragraph range in a TextBody shape in the source document
' to another TextBody shape in the target document.
Public Shared Sub MoveParagraphToPresentation(ByVal sourceFile As String, ByVal targetFile As String)
    ' Open the source file as read/write.
    Using sourceDoc As PresentationDocument = PresentationDocument.Open(sourceFile, True)
        ' Open the target file as read/write.
        Using targetDoc As PresentationDocument = PresentationDocument.Open(targetFile, True)
            ' Get the first slide in the source presentation.
            Dim slide1 As SlidePart = GetFirstSlide(sourceDoc)

            ' Get the first TextBody shape in it.
            Dim textBody1 As TextBody = slide1.Slide.Descendants(Of TextBody)().First()

            ' Get the first paragraph in the TextBody shape.
            ' Note: "Drawing" is the alias of namespace DocumentFormat.OpenXml.Drawing
            Dim p1 As Drawing.Paragraph = textBody1.Elements(Of Drawing.Paragraph)().First()

            ' Get the first slide in the target presentation.
            Dim slide2 As SlidePart = GetFirstSlide(targetDoc)

            ' Get the first TextBody shape in it.
            Dim textBody2 As TextBody = slide2.Slide.Descendants(Of 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(Of Drawing.Paragraph)(p1)

            ' Replace the removed paragraph with a placeholder.
            textBody1.AppendChild(Of Drawing.Paragraph)(New Drawing.Paragraph())

            ' Save the slide in the source file.
            slide1.Slide.Save()

            ' Save the slide in the target file.
            slide2.Slide.Save()
        End Using
    End Using
End Sub

GetFirstSlide 方法采用传入的 PresentationDocument 对象,获取演示文稿部件,再获取幻灯片列表中第一张幻灯片的 ID。然后获取该幻灯片的关系 ID,根据关系 ID 获取幻灯片部件,并将幻灯片部件返回到调用方法。

// Get the slide part of the first slide in the presentation document.
public static SlidePart GetFirstSlide(PresentationDocument presentationDocument)
{
    // Get relationship ID of the first slide
    PresentationPart part = presentationDocument.PresentationPart;
    SlideId slideId = part.Presentation.SlideIdList.GetFirstChild<SlideId>();
    string relId = slideId.RelationshipId;

    // Get the slide part by the relationship ID.
    SlidePart slidePart = (SlidePart)part.GetPartById(relId);

    return slidePart;
}
' Get the slide part of the first slide in the presentation document.
Public Shared Function GetFirstSlide(ByVal presentationDocument As PresentationDocument) As SlidePart
    ' Get relationship ID of the first slide
    Dim part As PresentationPart = presentationDocument.PresentationPart
    Dim slideId As SlideId = part.Presentation.SlideIdList.GetFirstChild(Of SlideId)()
    Dim relId As String = slideId.RelationshipId

    ' Get the slide part by the relationship ID.
    Dim slidePart As SlidePart = CType(part.GetPartById(relId), SlidePart)

    Return slidePart
End Function

示例代码

使用此示例代码可将一个演示文稿中的段落移动到另一个演示文稿中。在程序中,您可以使用对 MoveParagraphToPresentation 方法的以下调用将演示文稿文件"Myppt4.pptx"中的第一个段落移动到演示文稿文件"Myppt12.pptx"中。

string sourceFile = @"C:\Users\Public\Documents\Myppt4.pptx";
string targetFile = @"C:\Users\Public\Documents\Myppt12.pptx";
MoveParagraphToPresentation(sourceFile, targetFile);
Dim sourceFile As String = "C:\Users\Public\Documents\Myppt4.pptx"
Dim targetFile As String = "C:\Users\Public\Documents\Myppt12.pptx"
MoveParagraphToPresentation(sourceFile, targetFile)

运行程序后,查看源文件和目标文件的内容,便可看到移动的段落。

以下是使用 C# 和 Visual Basic 编写的完整示例代码。

// Moves a paragraph range in a TextBody shape in the source document
// to another TextBody shape in the target document.
public static void MoveParagraphToPresentation(string sourceFile, string targetFile)
{
    // Open the source file as read/write.
    using (PresentationDocument sourceDoc = PresentationDocument.Open(sourceFile, true))
    {
        // 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<Drawing.Paragraph>(p1);

            // Replace the removed paragraph with a placeholder.
            textBody1.AppendChild<Drawing.Paragraph>(new Drawing.Paragraph());

            // Save the slide in the source file.
            slide1.Slide.Save();

            // Save the slide in the target file.
            slide2.Slide.Save();
        }
    }
}

// Get the slide part of the first slide in the presentation document.
public static SlidePart GetFirstSlide(PresentationDocument presentationDocument)
{
    // Get relationship ID of the first slide
    PresentationPart part = presentationDocument.PresentationPart;
    SlideId slideId = part.Presentation.SlideIdList.GetFirstChild<SlideId>();
    string relId = slideId.RelationshipId;

    // Get the slide part by the relationship ID.
    SlidePart slidePart = (SlidePart)part.GetPartById(relId);

    return slidePart;
}
' Moves a paragraph range in a TextBody shape in the source document
' to another TextBody shape in the target document.
Public Sub MoveParagraphToPresentation(ByVal sourceFile As String, ByVal targetFile As String)

    ' Open the source file.
    Dim sourceDoc As PresentationDocument = PresentationDocument.Open(sourceFile, True)

    ' Open the target file.
    Dim targetDoc As PresentationDocument = PresentationDocument.Open(targetFile, True)

    ' Get the first slide in the source presentation.
    Dim slide1 As SlidePart = GetFirstSlide(sourceDoc)

    ' Get the first TextBody shape in it.
    Dim textBody1 As TextBody = slide1.Slide.Descendants(Of TextBody).First()

    ' Get the first paragraph in the TextBody shape.
    ' Note: Drawing is the alias of the namespace DocumentFormat.OpenXml.Drawing
    Dim p1 As Drawing.Paragraph = textBody1.Elements(Of Drawing.Paragraph).First()

    ' Get the first slide in the target presentation.
    Dim slide2 As SlidePart = GetFirstSlide(targetDoc)

    ' Get the first TextBody shape in it.
    Dim textBody2 As TextBody = slide2.Slide.Descendants(Of TextBody).First()

    ' Clone the source paragraph and insert the cloned paragraph into the target TextBody shape.
    textBody2.Append(p1.CloneNode(True))

    ' Remove the source paragraph from the source file.
    textBody1.RemoveChild(Of Drawing.Paragraph)(p1)

    ' Replace it with an empty one, because a paragraph is required for a TextBody shape.
    textBody1.AppendChild(Of Drawing.Paragraph)(New Drawing.Paragraph())

    ' Save the slide in the source file.
    slide1.Slide.Save()

    ' Save the slide in the target file.
    slide2.Slide.Save()

End Sub
' Get the slide part of the first slide in the presentation document.
Public Function GetFirstSlide(ByVal presentationDoc As PresentationDocument) As SlidePart

    ' Get relationship ID of the first slide.
    Dim part As PresentationPart = presentationDoc.PresentationPart
    Dim slideId As SlideId = part.Presentation.SlideIdList.GetFirstChild(Of SlideId)()
    Dim relId As String = slideId.RelationshipId

    ' Get the slide part by the relationship ID.
    Dim slidePart As SlidePart = CType(part.GetPartById(relId), SlidePart)

    Return slidePart

End Function

请参阅

引用

Class Library Reference