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


Заменить части стилей в текстовом редакторе

В этом разделе показано, как использовать классы в пакете SDK Open XML для Office для программной замены стилей в текстовом документе стилями из другого текстового документа. Он содержит пример ReplaceStyles метода для иллюстрации этой задачи, а также вспомогательные ReplaceStylesPart методы и ExtractStylesPart .


Сведения о хранилище стилей

Пакет текстовых документов, например файл с расширением .docx, на самом деле представляет собой файл .zip, состоящий из нескольких частей. Каждую часть можно представить как внешний файл. Часть имеет определенный тип контента и может содержать содержимое, равное содержимому внешнего XML-файла, двоичного файла, файла изображений и т. д. в зависимости от типа. Стандарт, который определяет, как открывать документы Open XML, хранимые в ZIP-файлах, называется Open Packaging Conventions. Дополнительные сведения о стандарте Open Packaging Conventions см. в спецификации ISO/IEC 29500-2.

Стили хранятся в выделенных частях в пакете текстовых документов. Документ Microsoft Word 2010, русская версия содержит одну часть стилей. Более поздние версии Microsoft Word добавить вторую часть stylesWithEffects. На следующем рисунке из документа Обозреватель в средстве open XML SDK Productivity Tool для Microsoft Office показаны части документа в примере документа Word 2013 и более поздних версий, содержащего стили.

Рис. 1. Стили в текстовом документе

Части стилей в текстовом документе.

Чтобы обеспечить "круговую передачу" документа с Word 2013 по Word 2010 и обратно, Word 2013+ сохраняет как часть исходных стилей, так и новые стили. (Спецификация форматов файлов Open XML в Office требует, чтобы корпорация Майкрософт Word игнорировать все части, которые она не распознает. Word 2010 не замечает часть stylesWithEffects, добавленную в документ Word 2013 и более поздних версий.)

Пример кода, приведенный в этом разделе, можно использовать для замены этих частей стилей.


Метод ReplaceStyles

С помощью ReplaceStyles примера метода можно заменить стили в текстовом документе стилями в другом текстовом документе. Метод ReplaceStyles принимает два параметра: первый параметр содержит строку, указывающую путь к файлу, который содержит стили для извлечения. Второй параметр содержит строку, указывающую путь к файлу, в который копируются стили, фактически полностью заменяя стили.

static void ReplaceStyles(string fromDoc, string toDoc)

Полный список кода для ReplaceStyles метода и его вспомогательных методов можно найти в разделе Пример кода .


Вызов примера метода

Чтобы вызвать пример метода, передайте строку для первого параметра, указывающего путь к файлу со стилями для извлечения, и строку для второго параметра, представляющую путь к файлу, в котором необходимо заменить стили. Следующий код показывает пример использования: После завершения выполнения кода стили в целевом документе будут заменены, и, следовательно, внешний вид текста в документе будет отражать новые стили.

string fromDoc = args[0];
string toDoc = args[1];

ReplaceStyles(fromDoc, toDoc);

Принципы работы кода

Код извлекает и заменяет часть стилей сначала, а затем часть stylesWithEffects второй и использует два вспомогательных метода для выполнения большей части работы. Метод ExtractStylesPart выполняет задание извлечения содержимого части стилей или stylesWithEffects и помещения его в XDocument объект . Метод ReplaceStylesPart принимает объект, созданный ExtractStylesPart и использует его содержимое для замены части стилей или stylesWithEffects в целевом документе.

// Extract and replace the styles part.
XDocument? node = ExtractStylesPart(fromDoc, false);

if (node is not null)
{
    ReplaceStylesPart(toDoc, node, false);
}

Последний параметр в сигнатуре для ExtractStylesPart метода или ReplaceStylesPart определяет, используется ли часть стилей или часть stylesWithEffects. Значение false указывает, что требуется извлечь и заменить часть стилей. Отсутствие значения (параметр необязательный) или значения true (значение по умолчанию) означает, что необходимо извлечь и заменить часть stylesWithEffects.

// Extract and replace the stylesWithEffects part. To fully support 
// round-tripping from Word 2010 to Word 2007, you should 
// replace this part, as well.
node = ExtractStylesPart(fromDoc);

if (node is not null)
{
    ReplaceStylesPart(toDoc, node);
}

return;

Дополнительные сведения о методе ExtractStylesPart см. в соответствующем примере. В следующем разделе описывается ReplaceStylesPart метод .


Метод ReplaceStylesPart

Метод ReplaceStylesPart можно использовать для замены стилей или части styleWithEffects в документе с учетом XDocument экземпляра, содержащего ту же часть для документа Word 2010 или Word 2013 и более поздних версий (как показано в примере кода ранее в этом разделе, ExtractStylesPart метод можно использовать для получения этого экземпляра). Метод ReplaceStylesPart принимает три параметра: первый параметр содержит строку, указывающую путь к файлу, который требуется изменить. Второй параметр содержит объект, содержащий часть стилей XDocument или стилейWithEffect из другого документа word, а третий указывает, требуется ли заменить часть стилей или часть stylesWithEffects (как показано в примере кода ранее в этом разделе, необходимо дважды вызвать эту процедуру для документов Word 2013 и более поздних версий, заменив каждую часть соответствующей частью из исходного документа).

static void ReplaceStylesPart(string fileName, XDocument newStyles, bool setStylesWithEffectsPart = true)

Принцип работы кода ReplaceStylesPart

Метод ReplaceStylesPart проверяет указанный документ и ищет стили или стилиWithEffects. Если запрошенная часть существует, метод сохраняет предоставленный XDocument объект в выбранной части.

Код начинается с открытия документа с помощью Open метода и указания, что документ должен быть открыт для чтения и записи (последний true параметр). При открытии документа код использует MainDocumentPart свойство для перехода к части документа main, а затем подготавливает переменную с именем stylesPart для хранения ссылки на часть стилей.

// Open the document for write access and get a reference.
using (var document = WordprocessingDocument.Open(fileName, true))
{
    if (document.MainDocumentPart is null || (document.MainDocumentPart.StyleDefinitionsPart is null && document.MainDocumentPart.StylesWithEffectsPart is null))
    {
        throw new ArgumentNullException("MainDocumentPart and/or one or both of the Styles parts is null.");
    }

    // Get a reference to the main document part.
    var docPart = document.MainDocumentPart;

    // Assign a reference to the appropriate part to the
    // stylesPart variable.

    StylesPart? stylesPart = null;

Поиск части "Правильные стили"

Затем код получает ссылку на запрошенную часть стилей с помощью setStylesWithEffectsPart логического параметра. На основе этого значения код получает ссылку на запрошенную часть стилей и сохраняет ее в переменной stylesPart .

if (setStylesWithEffectsPart)
{
    stylesPart = docPart.StylesWithEffectsPart;
}
else
{
    stylesPart = docPart.StyleDefinitionsPart;
}

Сохранение содержимого части

При условии, что запрошенная часть существует, код должен сохранить все содержимое объекта, XDocument переданного методу в часть. Каждая часть предоставляет GetStream() метод , который возвращает Stream. Код передает экземпляр Stream конструктору StreamWriter(Stream) класса , создавая модуль записи потока вокруг потока части. Наконец, код вызывает Save(Stream) метод XDocument, сохраняя его содержимое в части стилей.

// If the part exists, populate it with the new styles.
if (stylesPart is not null)
{
    newStyles.Save(new StreamWriter(stylesPart.GetStream(FileMode.Create, FileAccess.Write)));
}

Пример кода

Ниже приведены полные ReplaceStylesметоды , ReplaceStylesPartи ExtractStylesPart в C# и Visual Basic.

// Replace the styles in the "to" document with the styles in
// the "from" document.
static void ReplaceStyles(string fromDoc, string toDoc)
{

    // Extract and replace the styles part.
    XDocument? node = ExtractStylesPart(fromDoc, false);

    if (node is not null)
    {
        ReplaceStylesPart(toDoc, node, false);
    }

    // Extract and replace the stylesWithEffects part. To fully support 
    // round-tripping from Word 2010 to Word 2007, you should 
    // replace this part, as well.
    node = ExtractStylesPart(fromDoc);

    if (node is not null)
    {
        ReplaceStylesPart(toDoc, node);
    }

    return;
}

// Given a file and an XDocument instance that contains the content of 
// a styles or stylesWithEffects part, replace the styles in the file 
// with the styles in the XDocument.

static void ReplaceStylesPart(string fileName, XDocument newStyles, bool setStylesWithEffectsPart = true)
{

    // Open the document for write access and get a reference.
    using (var document = WordprocessingDocument.Open(fileName, true))
    {
        if (document.MainDocumentPart is null || (document.MainDocumentPart.StyleDefinitionsPart is null && document.MainDocumentPart.StylesWithEffectsPart is null))
        {
            throw new ArgumentNullException("MainDocumentPart and/or one or both of the Styles parts is null.");
        }

        // Get a reference to the main document part.
        var docPart = document.MainDocumentPart;

        // Assign a reference to the appropriate part to the
        // stylesPart variable.

        StylesPart? stylesPart = null;

        if (setStylesWithEffectsPart)
        {
            stylesPart = docPart.StylesWithEffectsPart;
        }
        else
        {
            stylesPart = docPart.StyleDefinitionsPart;
        }

        // If the part exists, populate it with the new styles.
        if (stylesPart is not null)
        {
            newStyles.Save(new StreamWriter(stylesPart.GetStream(FileMode.Create, FileAccess.Write)));
        }
    }
}

// Extract the styles or stylesWithEffects part from a 
// word processing document as an XDocument instance.
static XDocument ExtractStylesPart(string fileName, bool getStylesWithEffectsPart = true)
{
    // Declare a variable to hold the XDocument.
    XDocument? styles = null;

    // Open the document for read access and get a reference.
    using (var document = WordprocessingDocument.Open(fileName, false))
    {
        // Get a reference to the main document part.
        var docPart = document.MainDocumentPart;

        if (docPart is null)
        {
            throw new ArgumentNullException("MainDocumentPart is null.");
        }

        // Assign a reference to the appropriate part to the
        // stylesPart variable.
        StylesPart stylesPart;

        if (getStylesWithEffectsPart && docPart.StylesWithEffectsPart is not null)
        {
            stylesPart = docPart.StylesWithEffectsPart;
        }
        else if (docPart.StyleDefinitionsPart is not null)
        {
            stylesPart = docPart.StyleDefinitionsPart;
        }
        else
        {
            throw new ArgumentNullException("StyleWithEffectsPart and StyleDefinitionsPart are undefined");
        }

        using (var reader = XmlNodeReader.Create(stylesPart.GetStream(FileMode.Open, FileAccess.Read)))
        {
            // Create the XDocument.
            styles = XDocument.Load(reader);
        }
    }
    // Return the XDocument instance.
    return styles;
}

См. также