在演示文稿中获取幻灯片的所有文本

本主题演示如何使用 Open XML SDK for Office 中的类以编程方式获取演示文稿中幻灯片中的所有文本。


获取 PresentationDocument 对象

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

// Open the presentation as read-only.
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, false))

在 v3.0.0+ 中, Close() 已删除 方法,转而依赖于 using 语句。 这可确保在 Dispose() 到达右大括号时自动调用 方法。 语句后面的 using 块为在 语句中创建 using 或命名的对象建立作用域,在本例 presentationDocument中为 。


基本演示文稿文档结构

文档的基本文档结构PresentationML由多个部分组成,其中包括包含表示定义的main部分。 ISO/IEC 29500 规范中的以下文本介绍了包的整体PresentationML形式。

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

讲义 是可提供给访问群体 的一组打印的幻灯片。

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

文档可以包括以下其他功能 PresentationML动画音频视频和幻灯片之间的 切换 效果。

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

ISO/IEC 29500:2016

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

    <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 元素的强类型类创建文档结构和内容。 可以在 命名空间中找到 DocumentFormat.OpenXml.Presentation 这些类。 下表列出了对应于 、、 sldLayoutsldMasternotesMaster 元素的类的sld类名。

PresentationML 元素 Open XML SDK 类 说明
<sld/> Slide 演示文稿幻灯片。 它是 SlidePart 的根元素。
<sldLayout/> SlideLayout 幻灯片版式。 它是 SlideLayoutPart 的根元素。
<sldMaster/> SlideMaster 幻灯片母版。 它是 SlideMasterPart 的根元素。
<notesMaster/> NotesMaster 备注母版(或讲义母版)。 它是 NotesMasterPart 的根元素。

示例代码的工作方式

示例代码由 方法的三个 GetAllTextInSlide 重载组成。 在下面的代码段中,第一个重载的方法打开包含具有要获取文本的幻灯片的源演示文稿,并将此演示文稿传递给用于获取幻灯片部件的第二个重载的方法。 此方法返回第二个方法返回给它的字符串数组,其中每个字符串表示指定幻灯片中的一个文本段落。

// Get all the text in a slide.
public static string[] GetAllTextInSlide(string presentationFile, int slideIndex)
{
    // Open the presentation as read-only.
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, false))
    {
        // Pass the presentation and the slide index
        // to the next GetAllTextInSlide method, and
        // then return the array of strings it returns. 
        return GetAllTextInSlide(presentationDocument, slideIndex);
    }
}

第二个重载的方法采用传入的演示文稿文档并获取幻灯片部件以传递给第三个重载的方法。 此方法向第一个重载的方法返回第三个重载的方法返回给它的字符串数组,其中每个字符串表示指定幻灯片中的一个文本段落。

static string[] GetAllTextInSlide(PresentationDocument presentationDocument, int slideIndex)
{
    // Verify that the slide index is not out of range.
    if (slideIndex < 0)
    {
        throw new ArgumentOutOfRangeException("slideIndex");
    }

    // Get the presentation part of the presentation document.
    PresentationPart? presentationPart = presentationDocument.PresentationPart;

    // Verify that the presentation part and presentation exist.
    if (presentationPart is not null && presentationPart.Presentation is not null)
    {
        // Get the Presentation object from the presentation part.
        Presentation presentation = presentationPart.Presentation;

        // Verify that the slide ID list exists.
        if (presentation.SlideIdList is not null)
        {
            // Get the collection of slide IDs from the slide ID list.
            DocumentFormat.OpenXml.OpenXmlElementList slideIds = presentation.SlideIdList.ChildElements;

            // If the slide ID is in range...
            if (slideIndex < slideIds.Count)
            {
                // Get the relationship ID of the slide.
                string? slidePartRelationshipId = ((SlideId)slideIds[slideIndex]).RelationshipId;

                if (slidePartRelationshipId is null)
                {
                    return [];
                }

                // Get the specified slide part from the relationship ID.
                SlidePart slidePart = (SlidePart)presentationPart.GetPartById(slidePartRelationshipId);

                // Pass the slide part to the next method, and
                // then return the array of strings that method
                // returns to the previous method.
                return GetAllTextInSlide(slidePart);
            }
        }
    }

    // Else, return null.
    return [];
}

以下代码段显示第三个重载的方法,它采用传入的幻灯片部件,并向第二个重载的方法返回文本段落的字符串数组。 它首先验证传入的幻灯片部件是否存在,然后创建字符串的链接列表。 它循环访问传入的幻灯片中的段落,并使用 StringBuilder 对象连接段落中的所有文本行,将每个段落分配给链接列表中的一个字符串。 随后它向第二个重载的方法返回表示演示文稿中指定幻灯片内的所有文本的字符串数组。

static string[] GetAllTextInSlide(SlidePart slidePart)
{
    // Verify that the slide part exists.
    if (slidePart is null)
    {
        throw new ArgumentNullException("slidePart");
    }

    // Create a new linked list of strings.
    LinkedList<string> texts = new LinkedList<string>();

    // If the slide exists...
    if (slidePart.Slide is not null)
    {
        // Iterate through all the paragraphs in the slide.
        foreach (DocumentFormat.OpenXml.Drawing.Paragraph paragraph in
            slidePart.Slide.Descendants<DocumentFormat.OpenXml.Drawing.Paragraph>())
        {
            // Create a new string builder.                    
            StringBuilder paragraphText = new StringBuilder();

            // Iterate through the lines of the paragraph.
            foreach (DocumentFormat.OpenXml.Drawing.Text text in
                paragraph.Descendants<DocumentFormat.OpenXml.Drawing.Text>())
            {
                // Append each line to the previous lines.
                paragraphText.Append(text.Text);
            }

            if (paragraphText.Length > 0)
            {
                // Add each paragraph to the linked list.
                texts.AddLast(paragraphText.ToString());
            }
        }
    }

    // Return an array of strings.
    return texts.ToArray();
}

示例代码

以下是可用于获取演示文稿文件中特定幻灯片内的所有文本的完整示例代码。 例如,可以在程序中使用以下 foreach 循环来获取 方法 GetAllTextInSlide返回的字符串数组,该方法表示幻灯片中位于 的演示文稿文件的索引 slideIndexfilePath的文本。

foreach (string text in GetAllTextInSlide(filePath, int.Parse(slideIndex)))
{
    Console.WriteLine(text);
}

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

// Get all the text in a slide.
public static string[] GetAllTextInSlide(string presentationFile, int slideIndex)
{
    // Open the presentation as read-only.
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, false))
    {
        // Pass the presentation and the slide index
        // to the next GetAllTextInSlide method, and
        // then return the array of strings it returns. 
        return GetAllTextInSlide(presentationDocument, slideIndex);
    }
}
static string[] GetAllTextInSlide(PresentationDocument presentationDocument, int slideIndex)
{
    // Verify that the slide index is not out of range.
    if (slideIndex < 0)
    {
        throw new ArgumentOutOfRangeException("slideIndex");
    }

    // Get the presentation part of the presentation document.
    PresentationPart? presentationPart = presentationDocument.PresentationPart;

    // Verify that the presentation part and presentation exist.
    if (presentationPart is not null && presentationPart.Presentation is not null)
    {
        // Get the Presentation object from the presentation part.
        Presentation presentation = presentationPart.Presentation;

        // Verify that the slide ID list exists.
        if (presentation.SlideIdList is not null)
        {
            // Get the collection of slide IDs from the slide ID list.
            DocumentFormat.OpenXml.OpenXmlElementList slideIds = presentation.SlideIdList.ChildElements;

            // If the slide ID is in range...
            if (slideIndex < slideIds.Count)
            {
                // Get the relationship ID of the slide.
                string? slidePartRelationshipId = ((SlideId)slideIds[slideIndex]).RelationshipId;

                if (slidePartRelationshipId is null)
                {
                    return [];
                }

                // Get the specified slide part from the relationship ID.
                SlidePart slidePart = (SlidePart)presentationPart.GetPartById(slidePartRelationshipId);

                // Pass the slide part to the next method, and
                // then return the array of strings that method
                // returns to the previous method.
                return GetAllTextInSlide(slidePart);
            }
        }
    }

    // Else, return null.
    return [];
}
static string[] GetAllTextInSlide(SlidePart slidePart)
{
    // Verify that the slide part exists.
    if (slidePart is null)
    {
        throw new ArgumentNullException("slidePart");
    }

    // Create a new linked list of strings.
    LinkedList<string> texts = new LinkedList<string>();

    // If the slide exists...
    if (slidePart.Slide is not null)
    {
        // Iterate through all the paragraphs in the slide.
        foreach (DocumentFormat.OpenXml.Drawing.Paragraph paragraph in
            slidePart.Slide.Descendants<DocumentFormat.OpenXml.Drawing.Paragraph>())
        {
            // Create a new string builder.                    
            StringBuilder paragraphText = new StringBuilder();

            // Iterate through the lines of the paragraph.
            foreach (DocumentFormat.OpenXml.Drawing.Text text in
                paragraph.Descendants<DocumentFormat.OpenXml.Drawing.Text>())
            {
                // Append each line to the previous lines.
                paragraphText.Append(text.Text);
            }

            if (paragraphText.Length > 0)
            {
                // Add each paragraph to the linked list.
                texts.AddLast(paragraphText.ToString());
            }
        }
    }

    // Return an array of strings.
    return texts.ToArray();
}

另请参阅