Supprimer les commentaires de tous les auteurs ou d’un auteur spécifique dans un document de traitement de texte
Cette rubrique montre comment utiliser les classes du Kit de développement logiciel (SDK) Open XML pour Office pour supprimer par programmation les commentaires de tout ou d’un auteur spécifique dans un document de traitement de texte, sans avoir à charger le document dans Microsoft Word. Elle présente un exemple de la méthode DeleteComments pour illustrer cette tâche.
Méthode DeleteComments
La méthode DeleteComments permet de supprimer tous les commentaires d'un document de traitement de texte ou seulement ceux écrits par un auteur particulier. Comme le montre le code suivant, la méthode accepte deux paramètres pour indiquer le nom du document à modifier (chaîne) et, facultativement, le nom de l'auteur dont vous souhaitez supprimer les commentaires (chaîne). Si vous fournissez un nom d'auteur, le code supprime les commentaires écrits par l'auteur spécifié. Si vous ne fournissez pas de nom d'auteur, le code supprime tous les commentaires du document.
// 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 = "")
Appel de la méthode DeleteComments
Pour appeler la méthode DeleteComments, fournissez les paramètres requis comme dans le code suivant.
DeleteComments(@"C:\Users\Public\Documents\DeleteComments.docx",
"David Jones");
Fonctionnement du code
Le code ouvre d'abord le document à l'aide de la méthode WordprocessingDocument.Open en indiquant que le document doit être ouvert en accès lecture/écriture (la valeur finale true du paramètre). Ensuite, le code récupère une référence à la partie commentaires, à l’aide de la propriété WordprocessingCommentsPart du composant de document main, après avoir récupéré une référence au composant de document main à partir de la propriété MainDocumentPart du document de traitement de texte. Si la partie des commentaires est absente, il n'y a pas lieu de continuer, car il n'y a pas de commentaire à supprimer.
// 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…
}
Création de la liste de commentaires
Le code effectue ensuite deux tâches : la création d’une liste de tous les commentaires à supprimer et la création d’une liste d’ID de commentaire qui correspondent aux commentaires à supprimer. Compte tenu de ces listes, le code peut supprimer les commentaires de la partie commentaires qui contient les commentaires et supprimer les références aux commentaires du composant de document. Le code suivant commence par récupérer une liste d’éléments Comment . Pour récupérer la liste, elle convertit la collection Elements exposée par la variable commentPart en une liste d’objets Comment .
List<Comment> commentsToDelete =
commentPart.Comments.Elements<Comment>().ToList();
Jusqu'ici, la liste des commentaires contient tous les commentaires. Si le paramètre de l'auteur n'est pas une chaîne vide, le code suivant limite la liste aux seuls commentaires dont la propriété Author correspond au paramètre fourni.
if (!String.IsNullOrEmpty(author))
{
commentsToDelete = commentsToDelete.
Where(c => c.Author == author).ToList();
}
Avant de supprimer des commentaires, le code récupère une liste de valeurs d'ID de commentaires, afin qu'il puisse ultérieurement supprimer les éléments correspondants de la partie document. L’appel à la méthode Select projette efficacement la liste des commentaires, en récupérant un T> IEnumerable< de chaînes qui contiennent toutes les valeurs d’ID de commentaire.
IEnumerable<string> commentIds =
commentsToDelete.Select(r => r.Id.Value);
Suppression des commentaires et enregistrement de la partie
Disposant de la collection commentsToDelete, le code suivant boucle dans tous les commentaires nécessitant une suppression et exécute la suppression. Le code enregistre ensuite la partie des commentaires.
// Delete each comment in commentToDelete from the
// Comments collection.
foreach (Comment c in commentsToDelete)
{
c.Remove();
}
// Save the comment part changes.
commentPart.Comments.Save();
Suppression des références de commentaires dans le document
Bien que le code ait effectué la suppression de tous les commentaires à ce stade, cela ne suffit pas. Il doit également supprimer les références aux commentaires de la partie document. Cette action nécessite trois étapes, car la référence de commentaire inclut les éléments CommentRangeStart, CommentRangeEnd et CommentReference , et le code doit supprimer les trois pour chaque commentaire. Avant d'exécuter des suppressions, le code récupère d'abord une référence à l'élément racine de la partie principale du document, comme le montre le code suivant.
Document doc = document.MainDocumentPart.Document;
Disposant d'une référence à l'élément de document, le code suivant effectue trois boucles, une boucle pour chacun des éléments qu'il doit supprimer. Dans chaque cas, le code recherche tous les descendants du type correct (CommentRangeStart, CommentRangeEnd ou CommentReference) et limite la liste à ceux dont la valeur de propriété Id est contenue dans la liste des ID de commentaire à supprimer. En s'appuyant sur la liste des éléments à supprimer, le code supprime chaque élément à tour de rôle. Enfin, le code se termine en enregistrant le document.
// 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();
Exemple de code
Voici l’exemple de code complet en C# et en 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();
}
}