Excluir comentários de todos os autores ou de um autor específico em um documento de processamento de texto
Este tópico mostra como usar as classes no SDK Do Open XML para Office para excluir comentários de forma programática por todos ou por um autor específico em um documento de processamento de palavras, sem precisar carregar o documento no Microsoft Word. Ele contém um método DeleteComments de exemplo para ilustrar essa tarefa.
Método DeleteComments
Você pode usar o método DeleteComments para excluir todos os comentários de um documento de processamento de palavras ou apenas aqueles escritos por um autor específico. Conforme mostrado no código a seguir, o método aceita dois parâmetros que indicam o nome do documento para modificar (cadeia de caracteres) e, opcionalmente, o nome do autor cujos comentários você deseja excluir (cadeia de caracteres). Se você fornecer um nome de autor, o código excluirá comentários escritos pelo autor especificado. Se você não fornecer um nome de autor, o código excluirá todos os comentários.
// Delete comments by a specific author. Pass an empty string for the
// author to delete all comments, by all authors.
public static void DeleteComments(string fileName,
string author = "")
Chamando o método DeleteComments
Para chamar o método DeleteComments , forneça os parâmetros necessários, conforme mostrado no código a seguir.
DeleteComments(@"C:\Users\Public\Documents\DeleteComments.docx",
"David Jones");
Como o código funciona
O código a seguir começa abrindo o documento, usando o método WordprocessingDocument.Open e indicando que o documento deve estar aberto para acesso de leitura/gravação (o valor final do parâmetro verdadeiro ). Em seguida, o código recupera uma referência à parte de comentários, usando a propriedade WordprocessingCommentsPart da parte do documento main, depois de ter recuperado uma referência à parte do documento main da propriedade MainDocumentPart do documento de processamento de palavras. Se a parte de comentários estiver ausente, não haverá nenhum ponto em prosseguir, pois não pode haver comentários a serem excluídos.
// Get an existing Wordprocessing document.
using (WordprocessingDocument document =
WordprocessingDocument.Open(fileName, true))
{
// Set commentPart to the document WordprocessingCommentsPart,
// if it exists.
WordprocessingCommentsPart commentPart =
document.MainDocumentPart.WordprocessingCommentsPart;
// If no WordprocessingCommentsPart exists, there can be no
// comments. Stop execution and return from the method.
if (commentPart == null)
{
return;
}
// Code removed here…
}
Criando a Lista de Comentários
O código em seguida executa duas tarefas: criar uma lista de todos os comentários a serem excluídos e criar uma lista de IDs de comentário que correspondam aos comentários a serem excluídos. Dadas essas listas, o código pode excluir os comentários da parte de comentários que contém os comentários e excluir as referências aos comentários da parte do documento. O código a seguir começa recuperando uma lista de elementos comment . Para recuperar a lista, ela converte a coleção Elements exposta pela variável commentPart em uma lista de objetos Comment .
List<Comment> commentsToDelete =
commentPart.Comments.Elements<Comment>().ToList();
Até agora, a lista de comentários contém todos os comentários. Se o parâmetro do autor não for uma cadeia de caracteres vazia, o código a seguir limitará a lista apenas aos comentários em que a propriedade Author corresponde ao parâmetro fornecido.
if (!String.IsNullOrEmpty(author))
{
commentsToDelete = commentsToDelete.
Where(c => c.Author == author).ToList();
}
Antes de excluir qualquer comentário, o código recupera uma lista de valores de ID de comentários, para que ele possa posteriormente excluir elementos correspondentes da parte do documento. A chamada para o método Select projeta efetivamente a lista de comentários, recuperando um IEnumerable<T> de cadeias de caracteres que contêm todos os valores de ID de comentário.
IEnumerable<string> commentIds =
commentsToDelete.Select(r => r.Id.Value);
Excluindo comentários e salvando a parte
Dada a coleção commentsToDelete , para os loops de código a seguir, todos os comentários que exigem exclusão e executam a exclusão. Em seguida, o código salva a parte de comentários.
// Delete each comment in commentToDelete from the
// Comments collection.
foreach (Comment c in commentsToDelete)
{
c.Remove();
}
// Save the comment part changes.
commentPart.Comments.Save();
Excluindo referências de comentário no documento
Embora o código tenha removido com êxito todos os comentários por este ponto, isso não é suficiente. O código também deve remover referências aos comentários da parte do documento. Essa ação requer três etapas porque a referência de comentário inclui os elementos CommentRangeStart, CommentRangeEnd e CommentReference e o código deve remover todos os três para cada comentário. Antes de executar quaisquer exclusões, o código primeiro recupera uma referência ao elemento raiz da parte do documento main, conforme mostrado no código a seguir.
Document doc = document.MainDocumentPart.Document;
Dada uma referência ao elemento documento, o código a seguir executa seu loop de exclusão três vezes, uma vez para cada um dos diferentes elementos que ele deve excluir. Em cada caso, o código procura todos os descendentes do tipo correto (CommentRangeStart, CommentRangeEnd ou CommentReference) e limita a lista àqueles cujo valor da propriedade ID está contido na lista de IDs de comentário a serem excluídas. Dada a lista de elementos a serem excluídos, o código remove cada elemento por sua vez. Por fim, o código é concluído salvando o documento.
// Delete CommentRangeStart for each
// deleted comment in the main document.
List<CommentRangeStart> commentRangeStartToDelete =
doc.Descendants<CommentRangeStart>().
Where(c => commentIds.Contains(c.Id.Value)).ToList();
foreach (CommentRangeStart c in commentRangeStartToDelete)
{
c.Remove();
}
// Delete CommentRangeEnd for each deleted comment in the main document.
List<CommentRangeEnd> commentRangeEndToDelete =
doc.Descendants<CommentRangeEnd>().
Where(c => commentIds.Contains(c.Id.Value)).ToList();
foreach (CommentRangeEnd c in commentRangeEndToDelete)
{
c.Remove();
}
// Delete CommentReference for each deleted comment in the main document.
List<CommentReference> commentRangeReferenceToDelete =
doc.Descendants<CommentReference>().
Where(c => commentIds.Contains(c.Id.Value)).ToList();
foreach (CommentReference c in commentRangeReferenceToDelete)
{
c.Remove();
}
// Save changes back to the MainDocumentPart part.
doc.Save();
Código de exemplo
A seguir está um exemplo de código completo em C# e Visual Basic.
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections.Generic;
using System.Linq;
DeleteComments(args[0], args[1]);
// Delete comments by a specific author. Pass an empty string for the
// author to delete all comments, by all authors.
static void DeleteComments(string fileName, string author = "")
{
// Get an existing Wordprocessing document.
using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true))
{
if (document.MainDocumentPart is null || document.MainDocumentPart.WordprocessingCommentsPart is null)
{
throw new ArgumentNullException("MainDocumentPart and/or WordprocessingCommentsPart is null.");
}
// Set commentPart to the document WordprocessingCommentsPart,
// if it exists.
WordprocessingCommentsPart commentPart =
document.MainDocumentPart.WordprocessingCommentsPart;
// If no WordprocessingCommentsPart exists, there can be no
// comments. Stop execution and return from the method.
if (commentPart is null)
{
return;
}
// Create a list of comments by the specified author, or
// if the author name is empty, all authors.
List<Comment> commentsToDelete =
commentPart.Comments.Elements<Comment>().ToList();
if (!String.IsNullOrEmpty(author))
{
commentsToDelete = commentsToDelete.
Where(c => c.Author == author).ToList();
}
IEnumerable<string?> commentIds =
commentsToDelete.Where(r => r.Id is not null && r.Id.HasValue).Select(r => r.Id?.Value);
// Delete each comment in commentToDelete from the
// Comments collection.
foreach (Comment c in commentsToDelete)
{
c.Remove();
}
// Save the comment part change.
commentPart.Comments.Save();
Document doc = document.MainDocumentPart.Document;
// Delete CommentRangeStart for each
// deleted comment in the main document.
List<CommentRangeStart> commentRangeStartToDelete =
doc.Descendants<CommentRangeStart>().
Where(c => c.Id is not null && c.Id.HasValue && commentIds.Contains(c.Id.Value)).ToList();
foreach (CommentRangeStart c in commentRangeStartToDelete)
{
c.Remove();
}
// Delete CommentRangeEnd for each deleted comment in the main document.
List<CommentRangeEnd> commentRangeEndToDelete =
doc.Descendants<CommentRangeEnd>().
Where(c => c.Id is not null && c.Id.HasValue && commentIds.Contains(c.Id.Value)).ToList();
foreach (CommentRangeEnd c in commentRangeEndToDelete)
{
c.Remove();
}
// Delete CommentReference for each deleted comment in the main document.
List<CommentReference> commentRangeReferenceToDelete =
doc.Descendants<CommentReference>().
Where(c => c.Id is not null && c.Id.HasValue && commentIds.Contains(c.Id.Value)).ToList();
foreach (CommentReference c in commentRangeReferenceToDelete)
{
c.Remove();
}
// Save changes back to the MainDocumentPart part.
doc.Save();
}
}