Принять все изменения в текстовом документе
В этом разделе показано, как использовать пакет SDK Open XML для Office для принятия всех редакций в текстовом документе программным способом.
Структура документа WordProcessingML
Базовая структура WordProcessingML
документа состоит из document
элементов и body
, за которыми следует один или несколько элементов уровня блока, таких как p
, который представляет абзац. Абзац содержит один или несколько r
элементов. Представляет r
собой область текста с общим набором свойств, таких как форматирование. Выполнение содержит один или несколько t
элементов. Элемент t
содержит диапазон текста. В следующем примере кода показана разметка WordprocessingML
для документа, содержащего текст "Пример текста".
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:t>Example text.</w:t>
</w:r>
</w:p>
</w:body>
</w:document>
С помощью пакета SDK Open XML можно создавать структуру документа и содержимое с помощью строго типизированных классов, соответствующих WordprocessingML
элементам. Эти классы находятся в пространстве имен. В следующей таблице перечислены имена классов, которые соответствуют document
элементам , body
, p
, r
и t
.
Элемент WordprocessingML | Класс пакета SDK Open XML | Описание |
---|---|---|
<document/> |
Document | Корневой элемент основной части документа. |
<body/> |
Body | Контейнер для структур уровня блокировки, таких как абзацы, таблицы, примечания и других элементов, описанных в спецификации ISO/IEC 29500. |
<p/> |
Paragraph | Абзац. |
<r/> |
Run | Прогон. |
<t/> |
Text | Диапазон текста. |
Дополнительные сведения об общей структуре частей и элементов документа WordprocessingML см. в разделе Структура документа WordprocessingML.
Базовая структура WordProcessingML
документа состоит из document
элементов и body
, за которыми следует один или несколько элементов уровня блока, таких как p
, который представляет абзац. Абзац содержит один или несколько r
элементов. Представляет r
собой область текста с общим набором свойств, таких как форматирование. Выполнение содержит один или несколько t
элементов. Элемент t
содержит диапазон текста. В следующем примере кода показана разметка WordprocessingML
для документа, содержащего текст "Пример текста".
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:t>Example text.</w:t>
</w:r>
</w:p>
</w:body>
</w:document>
С помощью пакета SDK Open XML можно создавать структуру документа и содержимое с помощью строго типизированных классов, соответствующих WordprocessingML
элементам. Эти классы находятся в DocumentFormat.OpenXml.Wordprocessing пространстве имен. В следующей таблице перечислены имена классов, которые соответствуют document
элементам , body
, p
, r
и t
.
Элемент WordprocessingML | Класс пакета SDK Open XML | Описание |
---|---|---|
document | Document | Корневой элемент основной части документа. |
body | Body | Контейнер для структур уровня блокировки, таких как абзацы, таблицы, примечания и других элементов, описанных в спецификации ISO/IEC 29500. |
p | Paragraph | Абзац. |
r | Run | Прогон. |
t | Text | Диапазон текста. |
Элемент ParagraphPropertiesChange
Когда принимается исправление, свойства абзаца изменяются, поскольку удаляется существующий текст или вставляется новый текст. В следующих разделах вы узнаете о трех элементах, которые используются в коде для изменения содержимого абзаца, главным образом <w: pPrChange>
(сведения о редакции для свойств абзаца), <w:del>
(удаленный абзац) и <w:ins>
(вставленная строка таблицы).
В следующей информации из спецификации ISO/IEC 29500 представлен ParagraphPropertiesChange
элемент (pPrChange
).
*pPrChange (сведения о редакции для свойств абзаца)
Этот элемент определяет сведения об одном исправлении в наборе свойств абзаца в документе WordprocessingML.
Исправление хранится в документе следующим образом:
Дочерний элемент этого элемента содержит полный набор свойств абзаца на момент до исправления.
Атрибуты этого элемента содержат сведения о том, когда произошла эта редакция (другими словами, когда эти свойства стали "бывшим" набором свойств абзаца).
Рассмотрим абзац в документе WordprocessingML, к которому применяется выравнивание по центру, и это изменение свойств абзаца отслеживается как исправление. Данное исправление будет обозначено следующей разметкой WordprocessingML.
<w:pPr>
<w:jc w:val="center"/>
<w:pPrChange w:id="0" w:date="01-01-2006T12:00:00" w:author="Samantha Smith">
<w:pPr/>
</w:pPrChange>
</w:pPr>
Элемент указывает на то, что было внесено исправление в свойства абзаца 01.01.2006 пользователем Samantha Smith, и предыдущий набор свойств абзаца был нулевым (то есть в элементе не были явно указаны свойства абзаца).
pPr
pPrChange
© ISO/IEC 29500: 2016
Удаленный элемент
В следующей информации из спецификации ISO/IEC 29500 представлен элемент Deleted (del
).
del (удаленный абзац)
Этот элемент указывает, что знак абзаца, разделяющий конец абзаца в документе WordprocessingML, должен рассматриваться как удаленный (другими словами, содержимое этого абзаца больше не разделяется этим знаком абзаца и объединяется со следующим абзацем, но это содержимое не должно автоматически помечаться как удаленное) как часть отслеживаемой редакции.
Рассмотрим документ с двумя абзацами, каждый из которых ограничен знаком ¶:
Если физический символ, разделяющий конец первого абзаца, удаляется и это изменение отслеживается как редакция, результатом будет следующее:
Эта редакция представлена с помощью следующего кода WordprocessingML:
<w:p>
<w:pPr>
<w:rPr>
<w:del w:id="0" … />
</w:rPr>
</w:pPr>
<w:r>
<w:t>This is paragraph one.</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>This is paragraph two.</w:t>
</w:r>
</w:p>
Элемент del
в свойствах выполнения для первой метки абзаца указывает, что эта метка абзаца была удалена, и это удаление отслеживалось как редакция.
© ISO/IEC 29500: 2016
Вставленный элемент
В спецификации ISO/IEC 29500 представлен элемент Inserted (ins
).
ins (вставленная строка таблицы)
Этот элемент указывает на то, что родительская строка таблицы должна считаться вставленной строкой и эта вставка отслеживается как исправление. Этот параметр не предполагает установку какого-либо состояния исправления для ячеек таблицы в этой строке или для их содержимого (такие исправления должны отмечаться отдельно) и влияет только на саму строку таблицы.
Рассмотрим таблицу с двумя строками и двумя столбцами, в которой вторая строка отмечена как вставленная путем исправления. Это требование должно быть указано с помощью следующего кода WordprocessingML:
<w:tbl>
<w:tr>
<w:tc>
<w:p/>
</w:tc>
<w:tc>
<w:p/>
</w:tc>
</w:tr>
<w:tr>
<w:trPr>
<w:ins w:id="0" … />
</w:trPr>
<w:tc>
<w:p/>
</w:tc>
<w:tc>
<w:p/>
</w:tc>
</w:tr>
</w:tbl>
Элемент ins
в свойствах строки таблицы для второй строки таблицы указывает, что эта строка была вставлена, и эта вставка отслеживалась как редакция.
© ISO/IEC 29500: 2016
Пример кода
В следующем примере кода показано, как принять все исправления в текстовом документе.
После запуска программы откройте файл Word и убедитесь, что все исправления были приняты.
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections.Generic;
using System.Linq;
AcceptAllRevisions(args[0], args[1]);
static void AcceptAllRevisions(string fileName, string authorName)
{
using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(fileName, true))
{
if (wdDoc.MainDocumentPart is null || wdDoc.MainDocumentPart.Document.Body is null)
{
throw new ArgumentNullException("MainDocumentPart and/or Body is null.");
}
Body body = wdDoc.MainDocumentPart.Document.Body;
// Handle the formatting changes.
List<OpenXmlElement> changes = body.Descendants<ParagraphPropertiesChange>()
.Where(c => c.Author is not null && c.Author.Value == authorName).Cast<OpenXmlElement>().ToList();
foreach (OpenXmlElement change in changes)
{
change.Remove();
}
// Handle the deletions.
List<OpenXmlElement> deletions = body
.Descendants<Deleted>()
.Where(c => c.Author is not null && c.Author.Value == authorName)
.Cast<OpenXmlElement>().ToList();
deletions.AddRange(body.Descendants<DeletedRun>()
.Where(c => c.Author is not null && c.Author.Value == authorName).Cast<OpenXmlElement>().ToList());
deletions.AddRange(body.Descendants<DeletedMathControl>()
.Where(c => c.Author is not null && c.Author.Value == authorName).Cast<OpenXmlElement>().ToList());
foreach (OpenXmlElement deletion in deletions)
{
deletion.Remove();
}
// Handle the insertions.
List<OpenXmlElement> insertions =
body.Descendants<Inserted>()
.Where(c => c.Author is not null && c.Author.Value == authorName).Cast<OpenXmlElement>().ToList();
insertions.AddRange(body.Descendants<InsertedRun>()
.Where(c => c.Author is not null && c.Author.Value == authorName).Cast<OpenXmlElement>().ToList());
insertions.AddRange(body.Descendants<InsertedMathControl>()
.Where(c => c.Author is not null && c.Author.Value == authorName).Cast<OpenXmlElement>().ToList());
foreach (OpenXmlElement insertion in insertions)
{
// Found new content.
// Promote them to the same level as node, and then delete the node.
foreach (var run in insertion.Elements<Run>())
{
if (run == insertion.FirstChild)
{
insertion.InsertAfterSelf(new Run(run.OuterXml));
}
else
{
OpenXmlElement nextSibling = insertion.NextSibling()!;
nextSibling.InsertAfterSelf(new Run(run.OuterXml));
}
}
insertion.RemoveAttribute("rsidR", "https://schemas.openxmlformats.org/wordprocessingml/2006/main");
insertion.RemoveAttribute("rsidRPr", "https://schemas.openxmlformats.org/wordprocessingml/2006/main");
insertion.Remove();
}
}
}