Deleting Slides Using Open XML SDK 2.0

I usually like to use the Linq objects (XDpcument, XElement) when searching and modifying OpenXML documents. However, I know a lot of people prefer to use the specific objects available in version 2.0 of the SDK. For simple operations, this approach can work pretty well. I decided to try this approach while modifying an example I found in the forums that deletes hidden slides in a presentation. This example can be used as follows:

using (PresentationDocument pdoc = PresentationDocument.Open("Default.pptx", true))
{
   
SlideId _slideId = GetHiddenSlide(pdoc);
   
if (_slideId != null)
       
DeleteSlide(pdoc, _slideId);
    pdoc
.Close();
}

The GetHiddenSlide method will return the SlideId object for the slide to be deleted. DeleteSlide will delete the slide object specified. Of course, this will only delete the first hidden slide in the presentation. Deleting multiple hidden slides would require looping until GetHiddenSlide returns null, or changing GetHiddenSlide to return a list of SlideId objects.

// Get the presentation object and pass it to the next CountSlides method.
public static SlideId GetHiddenSlide(PresentationDocument presentationDocument)
{
   
// Open the presentation as read-only.
       
SlideId slideId = null;
       
foreach (SlidePart slide in presentationDocument.PresentationPart.SlideParts)
       
{
           
if (slide.Slide.Show != null && !slide.Slide.Show)
           
{
               
string slideRelId = presentationDocument.PresentationPart.GetIdOfPart(slide);
               
// Get the slide ID of the specified slide
                slideId
= presentationDocument.PresentationPart.Presentation.SlideIdList.ChildElements.Where(
                    s
=> ((SlideId)s).RelationshipId == slideRelId).FirstOrDefault() as SlideId;
               
break;
           
}
       
}
       
// Pass the presentation to the next CountSlide method
       
// and return the slide count.
       
return slideId;
}

Here is the first example of using the SlideId object in a Linq query. Once the hidden slide is located, the Linq query is used to find the matching SlideId object in the presentation. That object is the one that will need to be removed from the presentation part. Conveniently, it also contains the relationship ID of the slide, which can be used to easily delete the slide part. All of that is done in the next method:

// Delete the specified slide from the presentation.
public static void DeleteSlide(PresentationDocument presentationDocument, SlideId slideId)
{
   
if (presentationDocument == null)
   
{
       
throw new ArgumentNullException("presentationDocument");
   
}
   
// Get the presentation from the presentation part.
   
Presentation presentation = presentationDocument.PresentationPart.Presentation;
   
// Remove the slide from the slide list.
    presentation
.SlideIdList.RemoveChild(slideId);

   
// Get the relationship ID of the slide.
   
string slideRelId = slideId.RelationshipId;
   
//// Remove references to the slide from all custom shows.
   
if (presentation.CustomShowList != null)
   
{
       
// Iterate through the list of custom shows.
       
foreach (var customShow in presentation.CustomShowList.Elements<CustomShow>())
       
{
           
if (customShow.SlideList != null)
           
{
               
SlideListEntry entry = customShow.SlideList.ChildElements.Where(s => ((SlideListEntry)s).Id == slideRelId).FirstOrDefault() as SlideListEntry;
               
if (entry != null)
                    customShow
.SlideList.RemoveChild(entry);
           
}
       
}
   
}
   
// Save the modified presentation.
    presentation
.Save();

   
// Remove the slide part.
    presentationDocument
.PresentationPart.DeletePart(slideRelId);
}

There are three steps to deleting a slide. First, the SlideId entry is removed from the SlideIdList in the presentation part. Second, the slide may be referenced from any number of custom slide shows. The middle of the method iterates through the list of shows, but then uses a Linq query to find a matching entry in the show, if any, and delete it. Third, the slide part needs to be removed from the document. That can be done using the relationship ID for the slide.

Notice that even though the Linq queries use generic objects, they can be easily cast to the appropriate object from the SDK 2.0. If it is not convenient to use the SlideId object for the delete method, then you could use a relationship ID instead and move the Linq query from GetHiddenSlide into the delete.