Excluir todos os comentários feitos por um autor de todos os slides de uma apresentação
Este tópico mostra como utilizar as classes no SDK Open XML para o Office para eliminar todos os comentários de um autor específico numa apresentação através de programação.
Observação
Este exemplo destina-se a comentários modernos do PowerPoint. Para comentários clássicos, veja o exemplo arquivado no GitHub.
Obter um Objeto PresentationDocument
No SDK Open XML, a PresentationDocument classe representa um pacote de documento de apresentação. Para trabalhar com um documento de apresentação, crie primeiro uma instância da PresentationDocument
classe e, em seguida, trabalhe com essa instância. Para criar a instância de classe a partir do documento, chame o Open método que utiliza um caminho de ficheiro e um valor Booleano como segundo parâmetro para especificar se um documento é editável. Para abrir um documento para leitura/escrita, especifique o valor true
para este parâmetro, conforme mostrado na instrução seguinte using
.
Neste código, o parâmetro fileName é uma cadeia que representa o caminho para o ficheiro a partir do qual pretende abrir o documento e o autor é o nome de utilizador apresentado no separador Geral das Opções do PowerPoint.
using (PresentationDocument doc = PresentationDocument.Open(fileName, true))
Com a v3.0.0+ o Close() método foi removido a favor de depender da instrução using.
Isto garante que o Dispose() método é chamado automaticamente quando a chaveta de fecho é atingida. O bloco que segue a using
instrução estabelece um âmbito para o objeto que é criado ou nomeado na using
instrução , neste caso doc
.
Estrutura básica do documento de apresentação
A estrutura de documentos básica de um PresentationML
documento consiste em várias partes, entre as quais a main parte que contém a definição da apresentação. O texto seguinte da especificação ISO/IEC 29500 apresenta a forma geral de um PresentationML
pacote.
O main parte de um
PresentationML
pacote começa com um elemento raiz de apresentação. Esse elemento contém uma apresentação que, por sua vez, se refere a uma lista de diapositivos, a uma lista de master de diapositivos, a uma lista de notas master e a um folheto master lista. A lista de diapositivos refere-se a todos os diapositivos na apresentação; A lista de master de diapositivos refere-se a todos os modelos globais de diapositivos utilizados na apresentação; as notas master contêm informações sobre a formatação das páginas de notas; e o master de folheto descreve o aspeto de um folheto.Um folheto é um conjunto impresso de diapositivos que podem ser fornecidos a uma audiência.
Além de texto e gráficos, cada diapositivo pode conter comentários e notas, pode ter um esquema e pode fazer parte de uma ou mais apresentações personalizadas. Um comentário é uma anotação destinada à pessoa que mantém o conjunto de diapositivos da apresentação. Uma nota é um lembrete ou texto destinado ao apresentador ou à audiência.
Outras funcionalidades que um
PresentationML
documento pode incluir: animação, áudio, vídeo e transições entre diapositivos.Um
PresentationML
documento não é armazenado como um corpo grande numa única parte. Em vez disso, os elementos que implementam determinados agrupamentos de funcionalidades são armazenados em partes separadas. Por exemplo, todos os autores num documento são armazenados numa parte dos autores, enquanto cada diapositivo tem a sua própria parte.ISO/IEC 29500: 2016
O seguinte exemplo de código XML representa uma apresentação que contém dois diapositivos indicados pelos IDs 267 e 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>
Com o SDK Open XML, pode criar a estrutura e o conteúdo do documento com classes com tipos fortes que correspondem a elementos PresentationML. Pode encontrar estas classes no espaço de nomes. A tabela seguinte lista os nomes das classes que correspondem aos sld
elementos , sldLayout
, sldMaster
e notesMaster
.
Elemento PresentationML | Abrir Classe SDK XML | Descrição |
---|---|---|
<sld/> |
Slide | Diapositivo de Apresentação. É o elemento raiz de SlidePart. |
<sldLayout/> |
SlideLayout | Esquema de Diapositivo. É o elemento raiz de SlideLayoutPart. |
<sldMaster/> |
SlideMaster | Modelo Global de Diapositivos. É o elemento raiz de SlideMasterPart. |
<notesMaster/> |
NotesMaster | Modelo Global de Notas (ou handoutMaster). É o elemento raiz de NotesMasterPart. |
A Estrutura do Elemento de Comentário
O texto seguinte da especificação ISO/IEC 29500 apresenta comentários num pacote de apresentação.
Um comentário é uma nota de texto anexada a um diapositivo, com o objetivo principal de permitir que os leitores de uma apresentação forneçam feedback ao autor da apresentação. Cada comentário contém uma cadeia de texto não formatado e informações sobre o autor e está anexado a uma localização específica num diapositivo. Os comentários podem ser visíveis durante a edição da apresentação, mas não aparecem quando é dada uma apresentação de diapositivos. A aplicação de apresentação decide quando apresentar comentários e determina o aspeto do elemento visual.
© ISO/IEC 29500: 2016
A Estrutura do Elemento de Comentário Moderno
O seguinte elemento XML especifica um único comentário.
Contém o texto do comentário (t
) e os atributos que se referem ao respetivo autor (authorId
), data e hora de criação (created
) e id de comentário (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>
As tabelas seguintes listam as definições dos possíveis elementos subordinados e atributos do cm
elemento (comentário). Para obter a definição completa, consulte MS-PPTX 2.16.3.3 CT_Comment
Atributo | Definição |
---|---|
id | Especifica o ID de um comentário ou uma resposta de comentário. |
authorId | Especifica o ID de autor de um comentário ou uma resposta de comentário. |
status | Especifica a status de um comentário ou uma resposta de comentário. |
criadas | Especifica a data/hora em que o comentário ou a resposta ao comentário são criados. |
startDate | Especifica a data de início do comentário. |
dueDate | Especifica a data para conclusão do comentário. |
assignedTo | Especifica uma lista de autores a quem o comentário é atribuído. |
complete | Especifica a percentagem de conclusão do comentário. |
title | Especifica o título de um comentário. |
Elemento Filho | Definição |
---|---|
pc:sldMkLst | Especifica um nome de conteúdo que identifica o diapositivo ao qual o comentário está ancorado. |
ac:deMkLst | Especifica um moniker de conteúdo que identifica o elemento de desenho ao qual o comentário está ancorado. |
ac:txMkLst | Especifica um nome de conteúdo que identifica o intervalo de carateres de texto ao qual o comentário está ancorado. |
unknownAnchor | Especifica uma âncora desconhecida à qual o comentário está ancorado. |
pos | Especifica a posição do comentário, relativamente ao canto superior esquerdo do primeiro objeto ao qual o comentário está ancorado. |
replyLst | Especifica a lista de respostas ao comentário. |
txBody | Especifica o texto de um comentário ou uma resposta de comentário. |
extLst | Especifica uma lista de extensões para um comentário ou uma resposta de comentário. |
O seguinte exemplo de esquema XML define os membros do elemento para além dos cm
atributos obrigatórios e opcionais.
<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>
Como funciona o código de exemplo
Depois de abrir o documento de apresentação para acesso de leitura/escrita e instanciar a PresentationDocument
classe, o código obtém o autor do comentário especificado a partir da lista de autores de comentários.
// 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));
Ao iterar os autores correspondentes e todos os diapositivos na apresentação, o código obtém todas as partes do diapositivo e a parte dos comentários de cada parte do diapositivo. Em seguida, obtém a lista de comentários pelo autor especificado e elimina cada um deles. Também verifica se a parte do comentário não tem nenhum comentário existente, caso em que elimina essa parte. Também elimina o autor do comentário da parte dos autores do comentário.
// 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 exemplo
O método seguinte utiliza como parâmetros o nome e o caminho do ficheiro de apresentação de origem e o nome do autor do comentário cujos comentários devem ser eliminados. Localiza todos os comentários do autor especificado na apresentação e elimina-os. Em seguida, elimina o autor do comentário da lista de autores de comentários.
Observação
Para obter o nome exato do autor, abra o ficheiro de apresentação, clique no item de menu Ficheiro e, em seguida, clique em Opções. A janela Opções do PowerPoint é aberta e o conteúdo do separador Geral é apresentado. O nome do autor tem de corresponder ao Nome de utilizador neste separador.
Este é o código de exemplo completo em C# e em 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);
}
}
}