从演示文稿中删除幻灯片

本主题演示如何使用 Open XML SDK for Office 以编程方式从演示文稿中删除幻灯片。 它还演示如何从任何可能存在的自定义放映中删除对幻灯片的所有引用。 若要删除演示文稿文件中的特定幻灯片,您首先需要知道演示文稿中幻灯片的数目。 因此,本操作方法中的代码分为两部分。 第一部分统计幻灯片数目,第二部分删除特定索引处的幻灯片。

注意

[!注释] 从更加复杂的演示文稿(如那些包含大纲视图设置的演示文稿)中删除幻灯片可能需要其他步骤(举例来说)。


获取 Presentation 对象

在 Open XML SDK 中 PresentationDocument , 类表示演示文稿文档包。 若要处理演示文稿文档,请先创建 类的 PresentationDocument 实例,然后使用该实例。 若要从文档创建类实例, Open 请调用方法重载之一。 本主题中的代码使用 Open 方法,该方法采用文件路径作为指定要打开的文件的第一个参数,将布尔值作为第二个参数来指定文档是否可编辑。 将此第二个参数设置为 以 false 打开文件进行只读访问,或者 true 如果要打开文件进行读/写访问,请将此参数设置为 。 本主题中的代码打开文件两次,一次用于统计幻灯片数,一次用于删除特定幻灯片。 计算演示文稿中的幻灯片数时,最好打开文件进行只读访问,以防止意外写入文件。 以下 using 语句打开文件进行只读访问。 在此代码示例中 presentationFile , 参数是一个字符串,表示要从中打开文档的文件的路径。

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

若要从演示文稿文件中删除幻灯片,请打开它进行读/写访问,如以下 using 语句所示。

// Open the source document as read/write.
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))

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

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

统计幻灯片的数目

示例代码由 方法的两个 CountSlides 重载组成。 第一个重载使用参数, string 第二个 PresentationDocument 重载使用参数。 在第一种方法 CountSlides 中,示例代码在 语句中 using 打开演示文稿文档。 然后, PresentationDocument 它将 对象传递给第二 CountSlides 个方法,该方法返回一个整数,表示演示文稿中的幻灯片数。

// Pass the presentation to the next CountSlide method
// and return the slide count.
return CountSlides(presentationDocument);

第二CountSlides种方法中,代码验证传入的对象PresentationDocument是否不是 null,如果不是 ,则从 PresentationDocument 对象获取 PresentationPart 对象。 使用 代码 SlideParts 获取并返回 slideCount。

if (presentationDocument is null)
{
    throw new ArgumentNullException("presentationDocument");
}

int slidesCount = 0;

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

// Get the slide count from the SlideParts.
if (presentationPart is not null)
{
    slidesCount = presentationPart.SlideParts.Count();
}

// Return the slide count to the previous method.
return slidesCount;

删除特定幻灯片

用于删除幻灯片的代码使用 方法的两个 DeleteSlide 重载。 第一个重载 DeleteSlide 方法采用两个参数:表示演示文稿文件名和路径的字符串,以及表示要删除的幻灯片从零开始的索引位置的整数。 它将打开演示文稿文件进行读/写访问,获取对象 PresentationDocument ,然后将该对象和索引号传递给下一个重载 DeleteSlide 方法,该方法执行删除。

// Get the presentation object and pass it to the next DeleteSlide method.
static void DeleteSlide(string presentationFile, int slideIndex)
{
    // Open the source document as read/write.
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        // Pass the source document and the index of the slide to be deleted to the next DeleteSlide method.
        DeleteSlide(presentationDocument, slideIndex);
    }
}

第二个重载 DeleteSlide 方法的第一部分使用 CountSlides 方法获取演示文稿中的幻灯片数。 然后获取演示文稿中幻灯片 ID 的列表,标识幻灯片列表中的指定幻灯片,并从幻灯片列表中移除该幻灯片。

// Delete the specified slide from the presentation.
static void DeleteSlide(PresentationDocument presentationDocument, int slideIndex)
{
    if (presentationDocument is null)
    {
        throw new ArgumentNullException(nameof(presentationDocument));
    }

    // Use the CountSlides sample to get the number of slides in the presentation.
    int slidesCount = CountSlides(presentationDocument);

    if (slideIndex < 0 || slideIndex >= slidesCount)
    {
        throw new ArgumentOutOfRangeException("slideIndex");
    }

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

    // Get the presentation from the presentation part.
    Presentation? presentation = presentationPart?.Presentation;

    // Get the list of slide IDs in the presentation.
    SlideIdList? slideIdList = presentation?.SlideIdList;

    // Get the slide ID of the specified slide
    SlideId? slideId = slideIdList?.ChildElements[slideIndex] as SlideId;

    // Get the relationship ID of the slide.
    string? slideRelId = slideId?.RelationshipId;

    // If there's no relationship ID, there's no slide to delete.
    if (slideRelId is null)
    {
        return;
    }

    // Remove the slide from the slide list.
    slideIdList!.RemoveChild(slideId);

第二个重载 DeleteSlide 方法的下一部分从自定义放映中删除对已删除幻灯片的所有引用。 为此,它循环访问自定义放映列表并循环访问每个自定义放映中的幻灯片列表。 然后它声明并实例化幻灯片列表项的链接列表,并使用已删除幻灯片的关系 ID 查找对该幻灯片的引用。 它将这些引用添加到幻灯片列表项的列表中,然后从各自的自定义放映的幻灯片列表中移除每个这样的引用。

// Remove references to the slide from all custom shows.
if (presentation!.CustomShowList is not null)
{
    // Iterate through the list of custom shows.
    foreach (var customShow in presentation.CustomShowList.Elements<CustomShow>())
    {
        if (customShow.SlideList is not null)
        {
            // Declare a link list of slide list entries.
            LinkedList<SlideListEntry> slideListEntries = new LinkedList<SlideListEntry>();
            foreach (SlideListEntry slideListEntry in customShow.SlideList.Elements())
            {
                // Find the slide reference to remove from the custom show.
                if (slideListEntry.Id is not null && slideListEntry.Id == slideRelId)
                {
                    slideListEntries.AddLast(slideListEntry);
                }
            }

            // Remove all references to the slide from the custom show.
            foreach (SlideListEntry slideListEntry in slideListEntries)
            {
                customShow.SlideList.RemoveChild(slideListEntry);
            }
        }
    }
}

最后,代码删除已删除幻灯片的幻灯片部件。

// Get the slide part for the specified slide.
SlidePart slidePart = (SlidePart)presentationPart!.GetPartById(slideRelId);

// Remove the slide part.
presentationPart.DeletePart(slidePart);

示例代码

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

// Get the presentation object and pass it to the next CountSlides method.
static int CountSlides(string presentationFile)
{
    // Open the presentation as read-only.
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, false))
    {
        // Pass the presentation to the next CountSlide method
        // and return the slide count.
        return CountSlides(presentationDocument);
    }
}

// Count the slides in the presentation.
static int CountSlides(PresentationDocument presentationDocument)
{
    if (presentationDocument is null)
    {
        throw new ArgumentNullException("presentationDocument");
    }

    int slidesCount = 0;

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

    // Get the slide count from the SlideParts.
    if (presentationPart is not null)
    {
        slidesCount = presentationPart.SlideParts.Count();
    }

    // Return the slide count to the previous method.
    return slidesCount;
}

// Get the presentation object and pass it to the next DeleteSlide method.
static void DeleteSlide(string presentationFile, int slideIndex)
{
    // Open the source document as read/write.
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        // Pass the source document and the index of the slide to be deleted to the next DeleteSlide method.
        DeleteSlide(presentationDocument, slideIndex);
    }
}
// Delete the specified slide from the presentation.
static void DeleteSlide(PresentationDocument presentationDocument, int slideIndex)
{
    if (presentationDocument is null)
    {
        throw new ArgumentNullException(nameof(presentationDocument));
    }

    // Use the CountSlides sample to get the number of slides in the presentation.
    int slidesCount = CountSlides(presentationDocument);

    if (slideIndex < 0 || slideIndex >= slidesCount)
    {
        throw new ArgumentOutOfRangeException("slideIndex");
    }

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

    // Get the presentation from the presentation part.
    Presentation? presentation = presentationPart?.Presentation;

    // Get the list of slide IDs in the presentation.
    SlideIdList? slideIdList = presentation?.SlideIdList;

    // Get the slide ID of the specified slide
    SlideId? slideId = slideIdList?.ChildElements[slideIndex] as SlideId;

    // Get the relationship ID of the slide.
    string? slideRelId = slideId?.RelationshipId;

    // If there's no relationship ID, there's no slide to delete.
    if (slideRelId is null)
    {
        return;
    }

    // Remove the slide from the slide list.
    slideIdList!.RemoveChild(slideId);

    // Remove references to the slide from all custom shows.
    if (presentation!.CustomShowList is not null)
    {
        // Iterate through the list of custom shows.
        foreach (var customShow in presentation.CustomShowList.Elements<CustomShow>())
        {
            if (customShow.SlideList is not null)
            {
                // Declare a link list of slide list entries.
                LinkedList<SlideListEntry> slideListEntries = new LinkedList<SlideListEntry>();
                foreach (SlideListEntry slideListEntry in customShow.SlideList.Elements())
                {
                    // Find the slide reference to remove from the custom show.
                    if (slideListEntry.Id is not null && slideListEntry.Id == slideRelId)
                    {
                        slideListEntries.AddLast(slideListEntry);
                    }
                }

                // Remove all references to the slide from the custom show.
                foreach (SlideListEntry slideListEntry in slideListEntries)
                {
                    customShow.SlideList.RemoveChild(slideListEntry);
                }
            }
        }
    }

    // Get the slide part for the specified slide.
    SlidePart slidePart = (SlidePart)presentationPart!.GetPartById(slideRelId);

    // Remove the slide part.
    presentationPart.DeletePart(slidePart);
}

另请参阅