Поделиться через


Принять все изменения в текстовом документе

В этом разделе показано, как использовать пакет 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();
        }
    }
}