Удалить все комментарии автора со всех слайдов в презентации
В этом разделе показано, как использовать классы в пакете SDK Open XML для Office для удаления всех комментариев определенного автора в презентации программным способом.
Примечание.
Этот пример предназначен для современных комментариев PowerPoint. Для классических комментариев просмотрите архивный пример на сайте GitHub.
Получение объекта PresentationDocument
В пакете SDK Open PresentationDocument XML класс представляет пакет документов презентации. Чтобы работать с документом презентации, сначала создайте экземпляр PresentationDocument
класса , а затем работайте с этим экземпляром. Чтобы создать экземпляр класса из документа, вызовите Open метод, использующий путь к файлу, и логическое значение в качестве второго параметра, чтобы указать, доступен ли документ для редактирования. Чтобы открыть документ для чтения и записи, укажите значение true
для этого параметра, как показано в следующей using
инструкции.
В этом примере кода параметр fileName является строкой и содержит путь к файлу, из которого необходимо открыть документ, а в качестве автора используется имя пользователя, отображаемое на вкладке "Общие" диалогового окна "Параметры PowerPoint".
using (PresentationDocument doc = PresentationDocument.Open(fileName, true))
В версии 3.0.0+ Close() метод был удален в пользу использования инструкции using.
Это гарантирует автоматический Dispose() вызов метода при достижении закрывающей фигурной скобки. Блок, следующий за using
оператором , устанавливает область для объекта, созданного или именованного в инструкцииusing
, в данном случае doc
.
Базовая структура документа презентации
Базовая структура PresentationML
документа состоит из нескольких частей, среди которых есть main часть, содержащая определение презентации. В следующем тексте из спецификации ISO/IEC 29500 представлена общая форма PresentationML
пакета.
Main часть
PresentationML
пакета начинается с корневого элемента презентации. Этот элемент содержит презентацию, которая, в свою очередь, ссылается на список слайдов, список образцов слайдов, список образцов заметок и список образцов раздаточных материалов. Список слайдов ссылается на все слайды в презентации; список образцов слайдов ссылается на все образцы слайдов, используемые в презентации; в списке образцов заметок содержатся данные о форматировании страниц заметок, а в списке образцов раздаточных материалов описан внешний вид раздаточных материалов.Раздаточные материалы представляют собой набор распечатанных слайдов, которые можно раздать слушателям для последующего использования.
Наряду с текстом и изображениями слайды могут содержать комментарии, заметки и разметку, а также могут входить в одну или несколько пользовательских презентаций. Комментарий представляет собой примечание, которое адресовано сотруднику, ответственному за обслуживание набора слайдов. Заметка представляет собой напоминание или отрывок текста, предназначенный для докладчика или для слушателей.
Другие функции документа
PresentationML
могут включать следующие: анимацию, звук, видео и переходы между слайдами.Документ
PresentationML
не хранится в виде одного большого текста в одной части. Элементы с определенной группировкой функций хранятся в различных частях. Например, все авторы в документе хранятся в одной части авторов, а каждый слайд имеет свою собственную часть.ISO/IEC 29500: 2016
Указанный ниже пример кода XML описывает презентацию, содержащую 2 слайда с идентификаторами 267 и 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>
С помощью пакета SDK Open XML можно создавать структуру документа и содержимое с помощью строго типизированных классов, соответствующих элементам PresentationML. Эти классы можно найти в пространстве имен. В следующей таблице перечислены имена классов, которые соответствуют sld
элементам , sldLayout
, sldMaster
и notesMaster
.
Элемент PresentationML | Класс пакета SDK Open XML | Описание |
---|---|---|
<sld/> |
Slide | Слайд презентации. Это корневой элемент части SlidePart. |
<sldLayout/> |
SlideLayout | Разметка слайда. Это корневой элемент части SlideLayoutPart. |
<sldMaster/> |
SlideMaster | Образец слайда. Это корневой элемент части SlideMasterPart. |
<notesMaster/> |
NotesMaster | Образец заметок (или handoutMaster). Это корневой элемент части NotesMasterPart. |
Структура элемента комментария
Следующий текст из спецификации ISO/IEC 29500 содержит комментарии в пакете презентации.
Комментарий — это текст, присоединяемый к слайду и позволяющий читателям отправить свои отзывы автору презентации. Каждый комментарий содержит неформатированную строку текста и информацию о ее авторе и присоединяется в определенном расположении на слайде. Комментарии могут отображаться при изменении презентации, но скрываются при демонстрации. Используемое для просмотра приложение определяет необходимость отображения комментариев и определяет их внешний вид.
© ISO/IEC 29500: 2016
Структура современного элемента comment
Следующий XML-элемент задает один комментарий.
Он содержит текст комментария (t
) и атрибуты, ссылающиеся на его автора (authorId
), созданнуюcreated
дату () и идентификатор комментария (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>
В следующих таблицах перечислены определения возможных дочерних элементов и атрибутов cm
элемента (comment). Полное определение см. в статье MS-PPTX 2.16.3.3 CT_Comment
Атрибут | Определение |
---|---|
id | Указывает идентификатор комментария или ответа примечания. |
authorId | Указывает идентификатор автора комментария или ответа примечания. |
status | Указывает состояние комментария или ответа примечания. |
создано | Указывает дату создания комментария или ответа примечания. |
startDate | Указывает дату начала комментария. |
dueDate | Указывает дату выполнения комментария. |
assignedTo | Указывает список авторов, которым назначен комментарий. |
complete | Указывает процент завершения комментария. |
title | Задает заголовок для комментария. |
Дочерний элемент | Определение |
---|---|
pc:sldMkLst | Указывает моникер содержимого, который определяет слайд, к которому привязан комментарий. |
ac:deMkLst | Указывает моникер содержимого, который определяет элемент рисования, к которому привязан комментарий. |
ac:txMkLst | Указывает моникер содержимого, который определяет диапазон текстовых символов, к которому привязан комментарий. |
unknownAnchor | Указывает неизвестная привязка, к которой привязан комментарий. |
pos | Указывает положение комментария относительно левого верхнего угла первого объекта, к которому привязан комментарий. |
replyLst | Указывает список ответов на комментарий. |
txBody | Указывает текст комментария или ответа примечания. |
extLst | Задает список расширений для комментария или ответа примечания. |
В следующем примере xml-схемы определяются члены cm
элемента в дополнение к обязательным и необязательным атрибутам.
<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>
Механизм работы примера кода
После открытия документа презентации для доступа на чтение и запись и создания экземпляра PresentationDocument
класса код получает указанного автора комментариев из списка авторов комментариев.
// 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));
Код выполняет итерацию по всем авторам и всем слайдам презентации и получает части слайдов, а также части комментариев каждой из них. Затем код получает список комментариев указанного автора и удаляет все комментарии. Кроме того, код проверяет, имеется ли комментарий в части комментария, и при обнаружении удаляет часть. Код удаляет автора из части авторов комментариев.
// 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);
}
Пример кода
Следующий метод принимает в качестве параметров исходное имя файла презентации, путь и имя автора, чьи комментарии нужно удалить. Он находит все комментарии указанного автора в презентации и удаляет их. Затем он удаляет автора из списка авторов комментариев.
Примечание.
Чтобы получить точное имя автора, откройте файл презентации, выберите пункт меню Файл , а затем выберите пункт Параметры. Откроется окно Параметры PowerPoint, отображающее содержимое вкладки Общие. Имя автора должно соответствовать имени пользователя на этой вкладке.
Далее представлен полный пример кода на языках C# и 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);
}
}
}