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 utilizar as classes no SDK Open XML para o Office para eliminar comentários de forma programática por todos ou por um autor específico num documento de processamento de palavras, sem ter de carregar o documento para o Microsoft Word. Contém um método de exemplo DeleteComments
para ilustrar esta tarefa.
Método DeleteComments
Pode utilizar o DeleteComments
método para eliminar todos os comentários de um documento de processamento de palavras ou apenas os escritos por um autor específico. Conforme mostrado no código seguinte, o método aceita dois parâmetros que indicam o nome do documento a modificar (cadeia) e, opcionalmente, o nome do autor cujos comentários pretende eliminar (cadeia). Se fornecer um nome de autor, o código elimina os comentários escritos pelo autor especificado. Se não fornecer um nome de autor, o código elimina todos os comentários.
// 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 = "")
Chamar o Método DeleteComments
Para chamar o DeleteComments
método , forneça os parâmetros necessários, conforme mostrado no código seguinte.
if (args is [{ } fileName, { } author])
{
DeleteComments(fileName, author);
}
else if (args is [{ } fileName2])
{
DeleteComments(fileName2);
}
Como Funciona o Código
O código seguinte começa por abrir o documento, utilizando o WordprocessingDocument.Open método e indicando que o documento deve estar aberto para acesso de leitura/escrita (o valor final true
do parâmetro). Em seguida, o código obtém uma referência à parte de comentários, utilizando a WordprocessingCommentsPart propriedade da parte do documento main, depois de ter obtido uma referência à parte do documento main a MainDocumentPart partir da propriedade do documento de processamento de palavras. Se a parte dos comentários estiver em falta, não faz sentido continuar, uma vez que não pode haver comentários a eliminar.
// Get an existing Wordprocessing document.
using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true))
{
if (document.MainDocumentPart is null)
{
throw new ArgumentNullException("MainDocumentPart 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;
}
Criar a Lista de Comentários
Em seguida, o código executa duas tarefas: criar uma lista de todos os comentários a eliminar e criar uma lista de IDs de comentário que correspondem aos comentários a eliminar. Tendo em conta estas listas, o código pode eliminar os comentários da parte dos comentários que contém os comentários e eliminar as referências aos comentários da parte do documento. O código seguinte começa por obter uma lista de Comment elementos. Para obter a lista, converte a Elements() coleção exposta pela commentPart
variável numa lista de Comment
objetos.
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 vazia, o código seguinte limita a lista apenas aos comentários em que a Author propriedade corresponde ao parâmetro que forneceu.
if (!String.IsNullOrEmpty(author))
{
commentsToDelete = commentsToDelete.Where(c => c.Author == author).ToList();
}
Antes de eliminar quaisquer comentários, o código obtém uma lista de valores de ID de comentários, para que possa eliminar posteriormente elementos correspondentes da parte do documento. A chamada para o Select método projeta efetivamente a lista de comentários, obtendo uma IEnumerable<T> das cadeias que contêm todos os valores de ID de comentário.
IEnumerable<string?> commentIds = commentsToDelete.Where(r => r.Id is not null && r.Id.HasValue).Select(r => r.Id?.Value);
Eliminar Comentários e Guardar a Peça
Dada a commentsToDelete
coleção, o código seguinte percorre todos os comentários que requerem a eliminação e efetua a eliminação.
// Delete each comment in commentToDelete from the
// Comments collection.
foreach (Comment c in commentsToDelete)
{
if (c is not null)
{
c.Remove();
}
}
Eliminar Referências de Comentários no Documento
Embora o código tenha removido com êxito todos os comentários até este momento, isso não é suficiente. O código também tem de remover referências aos comentários da parte do documento. Esta ação requer três passos porque a referência do comentário inclui os CommentRangeStartelementos , CommentRangeEnde CommentReference e o código tem de remover os três para cada comentário. Antes de efetuar quaisquer eliminações, o código obtém primeiro uma referência ao elemento raiz da parte do documento main, conforme mostrado no código seguinte.
Document doc = document.MainDocumentPart.Document;
Tendo em conta uma referência ao elemento do documento, o código seguinte efetua o ciclo de eliminação três vezes, uma vez para cada um dos diferentes elementos que tem de eliminar. Em cada caso, o código procura todos os descendentes do tipo correto (CommentRangeStart
, CommentRangeEnd
ou CommentReference
) e limita a lista àqueles cujo Id valor de propriedade está contido na lista de IDs de comentário a eliminar.
Tendo em conta a lista de elementos a eliminar, o código remove cada elemento por sua vez.
Por fim, o código é concluído ao guardar o documento.
// 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();
}
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;
// 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)
{
throw new ArgumentNullException("MainDocumentPart 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)
{
if (c is not null)
{
c.Remove();
}
}
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();
}
}
}