Löschen der Kommentare eines oder aller Autoren aus einem Textverarbeitungsdokument
In diesem Thema wird gezeigt, wie Sie die Klassen im Open XML SDK für Office verwenden, um Kommentare von allen oder einem bestimmten Autor in einem Textverarbeitungsdokument programmgesteuert zu löschen, ohne das Dokument in Microsoft Word laden zu müssen. Diese Aufgabe wird mithilfe eines Beispiels der DeleteComments-Methode veranschaulicht.
DeleteComments-Methode
Mit der DeleteComments-Methode können Sie alle Kommentare aus einem Textverarbeitungsdokument oder nur diejenigen eines bestimmten Autors löschen. Wie der folgende Code zeigt, akzeptiert die Methode zwei Parameter, die den Namen des zu ändernden Dokuments (Zeichenfolge) und optional den Namen des Autors angeben, dessen Kommentare Sie löschen möchten (Zeichenfolge). Wenn Sie einen Autorennamen angeben, löscht der Code Kommentare dieses Autors. Wenn Sie keinen Autorennamen angeben, löscht der Code alle Kommentare.
// 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 = "")
Aufrufen der DeleteComments-Methode
Geben Sie zum Aufrufen der DeleteComments-Methode die erforderlichen Parameter an (siehe den folgenden Code).
DeleteComments(@"C:\Users\Public\Documents\DeleteComments.docx",
"David Jones");
Funktionsweise des Codes
Der folgende Code beginnt mit dem Öffnen des Dokuments mithilfe der WordprocessingDocument.Open -Methode und gibt an, dass das Dokument mit Lese-/Schreibzugriff geöffnet werden soll (mit dem letzten Parameterwert true). Als Nächstes ruft der Code einen Verweis auf den Kommentarteil mithilfe der WordprocessingCommentsPart-Eigenschaft des Standard Dokumentteils ab, nachdem ein Verweis auf das Standard Dokumentteil aus der MainDocumentPart-Eigenschaft des Textverarbeitungsdokuments abgerufen wurde. Wenn der Kommentarteil fehlt, muss der Vorgang nicht fortgesetzt werden, da es keine zu löschenden Kommentare gibt.
// 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…
}
Erstellen einer Liste der Kommentare
Der Code führt als Nächstes zwei Aufgaben aus: Erstellen einer Liste aller zu löschenden Kommentare und Erstellen einer Liste von Kommentar-IDs, die den zu löschenden Kommentaren entsprechen. Bei diesen Listen kann der Code sowohl die Kommentare aus dem Kommentarteil löschen, der die Kommentare enthält, als auch die Verweise auf die Kommentare aus dem Dokumentteil. Der folgende Code ruft zunächst eine Liste von Comment-Elementen ab. Um die Liste abzurufen, konvertiert sie die Elements-Auflistung , die von der variablen commentPart verfügbar gemacht wird, in eine Liste von Comment-Objekten .
List<Comment> commentsToDelete =
commentPart.Comments.Elements<Comment>().ToList();
Bislang enthält die Liste der Kommentare alle Kommentare. Wenn der Autorenparameter nicht leer ist, begrenzt der folgende Code die Liste auf ausschließlich die Kommentare, bei denen die Author -Eigenschaft dem angegebenen Parameter entspricht.
if (!String.IsNullOrEmpty(author))
{
commentsToDelete = commentsToDelete.
Where(c => c.Author == author).ToList();
}
Vor dem Löschen von Kommentaren ruft der Code eine Liste der Kommentar-ID-Werte ab, um später übereinstimmende Elemente aus dem Dokumentteil zu löschen. Der Aufruf der Select-Methode projiziert effektiv die Liste der Kommentare und ruft ein IEnumerable<T> von Zeichenfolgen ab, die alle Kommentar-ID-Werte enthalten.
IEnumerable<string> commentIds =
commentsToDelete.Select(r => r.Id.Value);
Löschen von Kommentaren und Speichern des Teils
Unter Verwendung der commentsToDelete-Auflistung durchläuft der folgende Code alle Kommentare, die gelöscht werden sollen, und führt den Löschvorgang aus. Anschließend speichert der Code den Kommentarteil.
// Delete each comment in commentToDelete from the
// Comments collection.
foreach (Comment c in commentsToDelete)
{
c.Remove();
}
// Save the comment part changes.
commentPart.Comments.Save();
Löschen von Kommentarverweisen aus dem Dokument
Obgleich der Code an dieser Stelle alle Kommentare erfolgreich entfernt hat, reicht dies noch nicht aus. Der Code muss auch Verweise auf die Kommentare aus dem Dokumentteil entfernen. Diese Aktion erfordert drei Schritte, da der Kommentarverweis die Elemente CommentRangeStart, CommentRangeEnd und CommentReference enthält und der Code alle drei für jeden Kommentar entfernen muss. Vor den Löschvorgängen ruft der Code zunächst einen Verweis auf das Stammelement des Hauptdokumentteils ab (siehe den folgenden Code).
Document doc = document.MainDocumentPart.Document;
Bei einem Verweis auf das Dokumentelement führt der folgende Code seine Löschschleife dreimal aus, einmal für jedes der verschiedenen Elemente, die es löschen muss. In jedem Fall sucht der Code nach allen Nachfolgern des richtigen Typs (CommentRangeStart, CommentRangeEnd oder CommentReference) und beschränkt die Liste auf diejenigen, deren Id-Eigenschaftswert in der Liste der zu löschenden Kommentar-IDs enthalten ist. Angesichts der Liste der zu löschenden Elemente entfernt der Code jedes Element nacheinander. Schließlich wird der Code durch Speichern des Dokuments abgeschlossen.
// 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();
Beispielcode
Es folgt der vollständige Beispielcode in C# und 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();
}
}