Delete comments by all or a specific author in a word processing document

Deleting comments requires editing both the comments part and references in the main document body.

The comments part stores <w:comment/> elements with ids and author metadata. The main document story stores matching range and reference markers. Filtering by author should happen in the comments part first; then use the matching ids to remove references from document content.

Rust workflow

Filter the comments part by author, then remove the corresponding body markers:

#![allow(unused)]
fn main() {
pub fn delete_comments_by_author(
  path: &Path,
  author: Option<&str>,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
  let mut document = WordprocessingDocument::new_from_file_with_settings(path, lazy_settings())?;
  let main_part = document.main_document_part()?;
  let Some(comments_part) = main_part.wordprocessing_comments_part(&document) else {
    let mut buffer = Cursor::new(Vec::new());
    document.save(&mut buffer)?;
    return Ok(buffer.into_inner());
  };
  let comments_xml = comments_part.data_as_str(&document)?.unwrap_or_default();
  let deleted_ids = matching_comment_ids(comments_xml, author);
  let updated_comments = remove_comments_by_id(comments_xml, &deleted_ids);
  comments_part.set_data(&mut document, updated_comments.into_bytes())?;

  let document_xml = main_part.data_as_str(&document)?.unwrap_or_default();
  let updated_document = remove_comment_markers(document_xml, &deleted_ids);
  main_part.set_data(&mut document, updated_document.into_bytes())?;

  let mut buffer = Cursor::new(Vec::new());
  document.save(&mut buffer)?;
  Ok(buffer.into_inner())
}
}

For each deleted comment id, remove all matching commentRangeStart, commentRangeEnd, and commentReference elements from the main document. If a package has comments in headers, footers, footnotes, or endnotes, apply the same marker cleanup in those stories too.

In ooxmlsdk, generated schema types include Comments, Comment, CommentRangeStart, CommentRangeEnd, and CommentReference. MainDocumentPart::wordprocessing_comments_part(&document) locates the comments part when it exists.