Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este tema se muestra cómo usar las clases del SDK de Open XML para Office para eliminar mediante programación los comentarios de todos o de un autor específico en un documento de procesamiento de texto, sin tener que cargar el documento en Microsoft Word. Contiene un método de ejemplo DeleteComments
para ilustrar esta tarea.
Método DeleteComments
Puede usar el DeleteComments
método para eliminar todos los comentarios de un documento de procesamiento de texto, o solo los escritos por un autor específico. Tal como se muestra en el código siguiente, el método acepta dos parámetros que indican el nombre del documento que se desea transformar (cadena) y, opcionalmente, el nombre del autor cuyos comentarios se desean eliminar (cadena). Si se proporciona el nombre de un autor, el código eliminará los comentarios escritos por el autor especificado. Si no se proporciona el nombre de un autor, el código eliminará todos los comentarios.
// 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 = "")
Llamar al método DeleteComments
Para llamar al DeleteComments
método , proporcione los parámetros necesarios como se muestra en el código siguiente.
if (args is [{ } fileName, { } author])
{
DeleteComments(fileName, author);
}
else if (args is [{ } fileName2])
{
DeleteComments(fileName2);
}
Funcionamiento del código
El código siguiente comienza abriendo el documento, usando el WordprocessingDocument.Open método e indicando que el documento debe estar abierto para el acceso de lectura y escritura (el valor final true
del parámetro). A continuación, el código recupera una referencia a la parte de comentarios, utilizando la WordprocessingCommentsPart propiedad del elemento de documento principal, después de haber recuperado una referencia a la parte principal del documento de la MainDocumentPart propiedad del documento de procesamiento de texto. Si falta la parte de comentarios, no tiene sentido continuar, puesto que no puede haber ningún comentario por 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;
}
Crear la lista de comentarios
A continuación, el código realiza dos tareas: crear una lista de todos los comentarios que se van a eliminar y crear una lista de identificadores de comentario que corresponden a los comentarios que se van a eliminar. Dadas estas listas, el código puede eliminar los comentarios de la parte de comentarios que contiene los comentarios y eliminar las referencias a los comentarios de la parte del documento. El código siguiente comienza recuperando una lista de Comment elementos. Para recuperar la lista, convierte la Elements() colección expuesta por la commentPart
variable en una lista de Comment
objetos.
List<Comment> commentsToDelete = commentPart.Comments.Elements<Comment>().ToList();
Hasta ahora, la lista de comentarios contiene todos los comentarios. Si el parámetro author no es una cadena vacía, el código siguiente limita la lista a solo aquellos comentarios en los que la Author propiedad coincida con el parámetro proporcionado.
if (!String.IsNullOrEmpty(author))
{
commentsToDelete = commentsToDelete.Where(c => c.Author == author).ToList();
}
Antes de eliminar cualquier comentario, el código recupera una lista de valores de identificador de comentario, para poder eliminar más adelante los elementos coincidentes de la parte del documento. La llamada al Select método proyecta eficazmente la lista de comentarios, recuperando una IEnumerable<T> de las cadenas que contienen todos los valores de identificador de comentario.
IEnumerable<string?> commentIds = commentsToDelete.Where(r => r.Id is not null && r.Id.HasValue).Select(r => r.Id?.Value);
Eliminar comentarios y guardar la parte
Dada la commentsToDelete
colección, en el código siguiente se recorren en bucle todos los comentarios que requieren la eliminación y se realiza la eliminación.
// Delete each comment in commentToDelete from the
// Comments collection.
foreach (Comment c in commentsToDelete)
{
if (c is not null)
{
c.Remove();
}
}
Eliminar referencias a comentarios en el documento
Aunque en este punto el código ha quitado correctamente todos los comentarios, no resulta suficiente. El código también debe quitar las referencias a comentarios de la parte del documento. Esta acción requiere tres pasos porque la referencia de comentario incluye los CommentRangeStartelementos , CommentRangeEndy CommentReference y el código debe quitar los tres para cada comentario. Antes de cualquier eliminación, el código recupera primero una referencia al elemento raíz de la parte principal del documento, tal como se muestra en el código siguiente.
Document doc = document.MainDocumentPart.Document;
Según una referencia al elemento de documento, el código siguiente realiza su bucle de eliminación tres veces, una para cada uno de los distintos elementos que debe eliminar. En cada caso, el código busca todos los descendientes del tipo correcto (CommentRangeStart
, CommentRangeEnd
o CommentReference
) y limita la lista a aquellos cuyo Id valor de propiedad está incluido en la lista de identificadores de comentario que se van a eliminar.
Según la lista de elementos por eliminar, el código quita los elementos de uno en uno.
Por último, el código finaliza guardando el 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 ejemplo
A continuación se muestra el ejemplo de código completo en C# y 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();
}
}
}