Compartir a través de


Eliminar todos los comentarios de un autor de todas las diapositivas de una presentación

En este tema se muestra cómo usar las clases del SDK de Open XML para Office para eliminar todos los comentarios de un autor específico en una presentación mediante programación.

Nota:

Este ejemplo es para comentarios modernos de PowerPoint. En el caso de los comentarios clásicos, vea el ejemplo archivado en GitHub.

Obtención de un objeto PresentationDocument

En el SDK de Open XML, la PresentationDocument clase representa un paquete de documento de presentación. Para trabajar con un documento de presentación, cree primero una instancia de la PresentationDocument clase y, a continuación, trabaje con esa instancia. Para crear la instancia de clase a partir del documento, llame al Open método que usa una ruta de acceso de archivo y a un valor booleano como segundo parámetro para especificar si un documento es editable. Para abrir un documento de lectura y escritura, especifique el valor true de este parámetro como se muestra en la instrucción siguiente using . En este código, el parámetro fileName es una cadena que representa la ruta de acceso del archivo a partir del cual desea abrir el documento y el autor es el nombre de usuario mostrado en la pestaña General de Opciones de PowerPoint.

using (PresentationDocument doc = PresentationDocument.Open(fileName, true))

Con v3.0.0+ el Close() método se ha quitado en favor de confiar en la instrucción using. Esto garantiza que se llama automáticamente al Dispose() método cuando se alcanza la llave de cierre. El bloque que sigue a la using instrucción establece un ámbito para el objeto que se crea o se denomina en la using instrucción , en este caso doc.

Estructura básica de un documento de presentación

La estructura básica de un PresentationML documento consta de varias partes, entre las que se encuentra la parte principal que contiene la definición de presentación. El siguiente texto de la especificación ISO/IEC 29500 presenta la forma general de un PresentationML paquete.

La parte principal de un PresentationML paquete comienza con un elemento raíz de presentación. Dicho elemento contiene una presentación que, a su vez, hace referencia a una lista de diapositivas, a otra de patrones de diapositivas, a otra de patrones de notas y a otra de patrones de documentos. La lista de diapositivas hace referencia a todas las diapositivas de la presentación, la de patrones de diapositivas a todos los patrones de diapositivas que se han usado en la presentación, el patrón de notas contiene información acerca del formato de las páginas de notas y el patrón de documentos describe la apariencia de los documentos.

Un documento es un conjunto impreso de diapositivas que se pueden proporcionar a un público.

Al igual que el texto y los gráficos, cada diapositiva puede incluir comentarios y notas, tener un diseño y formar parte de una o varias presentaciones personalizadas. Un comentario es una anotación dirigida a la persona que se encarga del mantenimiento de las diapositivas de la presentación. Una nota es un aviso o texto dirigido al moderador o al público.

Otras características que un PresentationML documento puede incluir son las siguientes: animación, audio, vídeo y transiciones entre diapositivas .

Un PresentationML documento no se almacena como un cuerpo grande en una sola parte. En su lugar, los elementos que implementan ciertas agrupaciones de funcionalidades se almacenan en partes independientes. Por ejemplo, todos los autores de un documento se almacenan en una parte de autores mientras que cada diapositiva tiene su propia parte.

ISO/IEC 29500: 2016

El siguiente ejemplo de código XML representa una presentación que contiene dos diapositivas denotadas por los identificadores 267 y 256.

    <p:presentation xmlns:p="…" … > 
       <p:sldMasterIdLst>
          <p:sldMasterId
             xmlns:rel="https://…/relationships" rel:id="rId1"/>
       </p:sldMasterIdLst>
       <p:notesMasterIdLst>
          <p:notesMasterId
             xmlns:rel="https://…/relationships" rel:id="rId4"/>
       </p:notesMasterIdLst>
       <p:handoutMasterIdLst>
          <p:handoutMasterId
             xmlns:rel="https://…/relationships" rel:id="rId5"/>
       </p:handoutMasterIdLst>
       <p:sldIdLst>
          <p:sldId id="267"
             xmlns:rel="https://…/relationships" rel:id="rId2"/>
          <p:sldId id="256"
             xmlns:rel="https://…/relationships" rel:id="rId3"/>
       </p:sldIdLst>
           <p:sldSz cx="9144000" cy="6858000"/>
       <p:notesSz cx="6858000" cy="9144000"/>
    </p:presentation>

Con el SDK de Open XML, puede crear contenido y estructura de documentos mediante clases fuertemente tipadas que corresponden a elementos PresentationML. Puede encontrar estas clases en el espacio de DocumentFormat.OpenXml.Presentation nombres. En la tabla siguiente se enumeran los nombres de clase de las clases correspondientes a los sldelementos , sldLayout, sldMastery notesMaster .

Elemento de PresentationML Open XML SDK (clase) Descripción
<sld/> Slide Diapositiva de presentación. Es el elemento raíz de SlidePart.
<sldLayout/> SlideLayout Diseño de la diapositiva. Es el elemento raíz de SlideLayoutPart.
<sldMaster/> SlideMaster Patrón de diapositivas. Es el elemento raíz de SlideMasterPart.
<notesMaster/> NotesMaster Patrón de notas (o handoutMaster). Es el elemento raíz de NotesMasterPart.

Estructura del elemento Comment

El siguiente texto de la especificación ISO/IEC 29500 presenta los comentarios de un paquete de presentación.

Un comentario es una nota de texto adjunta a la diapositiva y su objetivo principal consiste en permitir a los lectores de una presentación proporcionar comentarios al autor de ésta. Cada comentario contiene una cadena de texto sin formato e información acerca del autor y está adjunto en una ubicación concreta de la diapositiva. Los comentarios pueden verse al editar la presentación, pero no al mostrarla. La aplicación que muestra la presentación decide cuándo mostrar los comentarios y determina su apariencia visual.

© ISO/IEC 29500: 2016

Estructura del elemento de comentario moderno

El siguiente elemento XML especifica un único comentario. Contiene el texto del comentario (t) y los atributos que hacen referencia a su autor (authorId), la fecha y hora de creación (created) y el identificador de comentario (id).

<p188:cm id="{62A8A96D-E5A8-4BFC-B993-A6EAE3907CAD}" authorId="{CD37207E-7903-4ED4-8AE8-017538D2DF7E}" created="2024-12-30T20:26:06.503">
  <p188:txBody>
      <a:bodyPr/>
      <a:lstStyle/>
      <a:p>
      <a:r>
          <a:t>Needs more cowbell</a:t>
      </a:r>
      </a:p>
  </p188:txBody>
</p188:cm>

En las tablas siguientes se enumeran las definiciones de los posibles elementos secundarios y atributos del cm elemento (comentario). Para obtener la definición completa, consulte MS-PPTX 2.16.3.3 CT_Comment

Atributo Definición
id Especifica el identificador de un comentario o una respuesta de comentario.
authorId Especifica el identificador de autor de un comentario o una respuesta de comentario.
status Especifica el estado de un comentario o una respuesta de comentario.
creado Especifica la fecha y hora en que se crea la respuesta de comentario o comentario.
startDate Especifica la fecha de inicio del comentario.
dueDate Especifica la fecha de vencimiento del comentario.
assignedTo Especifica una lista de autores a los que se asigna el comentario.
complete Especifica el porcentaje de finalización del comentario.
title Especifica el título de un comentario.
Elemento secundario Definición
pc:sldMkLst Especifica un moniker de contenido que identifica la diapositiva a la que está delimitado el comentario.
ac:deMkLst Especifica un moniker de contenido que identifica el elemento de dibujo al que está delimitado el comentario.
ac:txMkLst Especifica un moniker de contenido que identifica el intervalo de caracteres de texto al que está delimitado el comentario.
unknownAnchor Especifica un delimitador desconocido al que está delimitado el comentario.
Pos Especifica la posición del comentario, en relación con la esquina superior izquierda del primer objeto al que está delimitado el comentario.
replyLst Especifica la lista de respuestas al comentario.
txBody Especifica el texto de un comentario o una respuesta de comentario.
extLst Especifica una lista de extensiones para un comentario o una respuesta de comentario.

En el siguiente ejemplo de esquema XML se definen los miembros del cm elemento además de los atributos obligatorios y opcionales.

 <xsd:complexType name="CT_Comment">
   <xsd:sequence>
     <xsd:group ref="EG_CommentAnchor" minOccurs="1" maxOccurs="1"/>
     <xsd:element name="pos" type="a:CT_Point2D" minOccurs="0" maxOccurs="1"/>
     <xsd:element name="replyLst" type="CT_CommentReplyList" minOccurs="0" maxOccurs="1"/>
     <xsd:group ref="EG_CommentProperties" minOccurs="1" maxOccurs="1"/>
   </xsd:sequence>
   <xsd:attributeGroup ref="AG_CommentProperties"/>
   <xsd:attribute name="startDate" type="xsd:dateTime" use="optional"/>
   <xsd:attribute name="dueDate" type="xsd:dateTime" use="optional"/>
   <xsd:attribute name="assignedTo" type="ST_AuthorIdList" use="optional" default=""/>
   <xsd:attribute name="complete" type="s:ST_PositiveFixedPercentage" default="0%" use="optional"/>
   <xsd:attribute name="title" type="xsd:string" use="optional" default=""/>
 </xsd:complexType>

Funcionamiento del código de ejemplo

Después de abrir el documento de presentación para el acceso de lectura y escritura y crear una instancia de la PresentationDocument clase, el código obtiene el autor de comentarios especificado de la lista de autores de comentarios.

// Get the modern comments.
IEnumerable<Author>? commentAuthors = doc.PresentationPart?.authorsPart?.AuthorList.Elements<Author>()
    .Where(x => x.Name is not null && x.Name.HasValue && x.Name.Value!.Equals(author));

Al procesar una iteración de los autores coincidentes y de todas las diapositivas de la presentación, el código obtiene todas las partes de diapositiva y la parte de comentarios de cada uno de ellos. Posteriormente, obtiene la lista de comentarios del autor especificado y los elimina. También comprueba que no existen comentarios en la parte de comentarios, en cuyo caso elimina dicha parte. Además, elimina el autor del comentario de la parte de autores de comentarios.

// Iterate through all the matching authors.
foreach (Author commentAuthor in commentAuthors)
{
    string? authorId = commentAuthor.Id;
    IEnumerable<SlidePart>? slideParts = doc.PresentationPart?.SlideParts;

    // If there's no author ID or slide parts or slide parts, return.
    if (authorId is null || slideParts is null)
    {
        return;
    }

    // Iterate through all the slides and get the slide parts.
    foreach (SlidePart slide in slideParts)
    {
        IEnumerable<PowerPointCommentPart>? slideCommentsParts = slide.commentParts;

        // Get the list of comments.
        if (slideCommentsParts is not null)
        {
            IEnumerable<Tuple<PowerPointCommentPart, Comment>> commentsTup = slideCommentsParts
                .SelectMany(scp => scp.CommentList.Elements<Comment>()
                .Where(comment => comment.AuthorId is not null && comment.AuthorId == authorId)
                .Select(c => new Tuple<PowerPointCommentPart, Comment>(scp, c)));

            foreach (Tuple<PowerPointCommentPart, Comment> comment in commentsTup)
            {
                // Delete all the comments by the specified author.
                comment.Item1.CommentList.RemoveChild(comment.Item2);

                // If the commentPart has no existing comment.
                if (comment.Item1.CommentList.ChildElements.Count == 0)
                {
                    // Delete this part.
                    slide.DeletePart(comment.Item1);
                }
            }

        }
    }

    // Delete the comment author from the authors part.
    doc.PresentationPart?.authorsPart?.AuthorList.RemoveChild(commentAuthor);
}

Código de ejemplo

El siguiente método toma como parámetros el nombre de archivo de la presentación original y su ruta de acceso, y el nombre del autor cuyos comentarios se desea eliminar. Busca en la presentación todos los comentarios del autor especificado y los elimina. A continuación, elimina el autor de la lista de autores de comentarios.

Nota:

[!NOTA] Para obtener el nombre exacto del autor, abra el archivo de presentación, haga clic en el elemento de menú Archivo y, a continuación, elija Opciones. Se abrirá la ventana Opciones de PowerPoint y se mostrará el contenido de la pestaña General. El nombre del autor debe coincidir con el Nombre de usuario que aparece en esta pestaña.

A continuación se incluye el código de ejemplo completo en C# y Visual Basic.

// Remove all the comments in the slides by a certain x.
static void DeleteCommentsByAuthorInPresentation(string fileName, string author)
{
    using (PresentationDocument doc = PresentationDocument.Open(fileName, true))
    {
        // Get the modern comments.
        IEnumerable<Author>? commentAuthors = doc.PresentationPart?.authorsPart?.AuthorList.Elements<Author>()
            .Where(x => x.Name is not null && x.Name.HasValue && x.Name.Value!.Equals(author));

        if (commentAuthors is null)
        {
            return;
        }

        // Iterate through all the matching authors.
        foreach (Author commentAuthor in commentAuthors)
        {
            string? authorId = commentAuthor.Id;
            IEnumerable<SlidePart>? slideParts = doc.PresentationPart?.SlideParts;

            // If there's no author ID or slide parts or slide parts, return.
            if (authorId is null || slideParts is null)
            {
                return;
            }

            // Iterate through all the slides and get the slide parts.
            foreach (SlidePart slide in slideParts)
            {
                IEnumerable<PowerPointCommentPart>? slideCommentsParts = slide.commentParts;

                // Get the list of comments.
                if (slideCommentsParts is not null)
                {
                    IEnumerable<Tuple<PowerPointCommentPart, Comment>> commentsTup = slideCommentsParts
                        .SelectMany(scp => scp.CommentList.Elements<Comment>()
                        .Where(comment => comment.AuthorId is not null && comment.AuthorId == authorId)
                        .Select(c => new Tuple<PowerPointCommentPart, Comment>(scp, c)));

                    foreach (Tuple<PowerPointCommentPart, Comment> comment in commentsTup)
                    {
                        // Delete all the comments by the specified author.
                        comment.Item1.CommentList.RemoveChild(comment.Item2);

                        // If the commentPart has no existing comment.
                        if (comment.Item1.CommentList.ChildElements.Count == 0)
                        {
                            // Delete this part.
                            slide.DeletePart(comment.Item1);
                        }
                    }

                }
            }

            // Delete the comment author from the authors part.
            doc.PresentationPart?.authorsPart?.AuthorList.RemoveChild(commentAuthor);
        }
    }
}

Vea también