Compartilhar via


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, CommentRangeEndou 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();
        }
    }
}

Confira também