Delete all the comments by an author from all the slides in a presentation
Deleting comments by author requires scanning slide comment parts and matching each comment's author id against the presentation comment authors part.
This page describes modern PowerPoint comments. Classic comments have a different archived package shape and should be handled by a separate tested fixture.
Package model
A presentation comment is a text note attached to a slide. It stores unformatted text, author information, and a slide position. Comments can be visible while editing the presentation, but they are not part of the slide show; the viewing application decides when and how to display them.
The author list maps author ids to names and initials:
<p:cmAuthorLst xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
<p:cmAuthor id="0" name="Ada" initials="AL" lastIdx="3" clrIdx="0"/>
</p:cmAuthorLst>
Slide comment parts then use authorId:
<p:cm authorId="0" idx="1">
<p:text>Review this slide.</p:text>
</p:cm>
The author name must match the user name stored by PowerPoint. In the PowerPoint UI, that value is shown under File, Options, General.
Delete workflow
The upstream modern-comments sample follows this package traversal:
- Open the presentation for editing and get the presentation part.
- Read the comment authors part and find authors whose
namematches the requested author. - Iterate every slide part in the presentation.
- For each slide comment part, remove comments whose
authorIdmatches one of those author IDs. - If a slide comment part becomes empty, remove that comment part relationship.
- Remove the matched author entries from the comment authors part.
Rust workflow
Match classic comment author entries by name, scan slide comments parts, and remove comments with matching author ids:
#![allow(unused)] fn main() { pub fn delete_comments_by_author( path: &Path, author_name: &str, ) -> Result<Vec<u8>, Box<dyn std::error::Error>> { let mut document = PresentationDocument::new_from_file_with_settings(path, lazy_settings())?; let presentation_part = document.presentation_part()?; let Some(authors_part) = presentation_part.comment_authors_part(&document) else { let mut buffer = Cursor::new(Vec::new()); document.save(&mut buffer)?; return Ok(buffer.into_inner()); }; let authors_xml = authors_part.data_as_str(&document)?.unwrap_or_default(); let author_ids = comment_author_ids_by_name(authors_xml, author_name); let updated_authors_xml = remove_comment_authors_by_id(authors_xml, &author_ids); authors_part.set_data(&mut document, updated_authors_xml.into_bytes())?; let slide_parts: Vec<_> = presentation_part.slide_parts(&document).collect(); for slide_part in slide_parts { let Some(comments_part) = slide_part.slide_comments_part(&document) else { continue; }; let comments_xml = comments_part.data_as_str(&document)?.unwrap_or_default(); let updated_comments_xml = remove_slide_comments_by_author_id(comments_xml, &author_ids); comments_part.set_data(&mut document, updated_comments_xml.into_bytes())?; } let mut buffer = Cursor::new(Vec::new()); document.save(&mut buffer)?; Ok(buffer.into_inner()) } }
Modern threaded comments use different parts and metadata. Apply the same author-id filtering idea there only after adding fixtures for those modern parts.