Compartilhar via


Aplicar estilo a um parágrafo em documento de processamento de texto

Este tópico mostra como utilizar as classes no SDK Open XML para o Office para aplicar programaticamente um estilo a um parágrafo num documento de processamento de palavras. Contém um método de exemplo ApplyStyleToParagraph para ilustrar esta tarefa, além de vários métodos de exemplo suplementares para marcar se existe um estilo, adicionar um novo estilo e adicionar a parte estilos.

ApplyStyleToParagraph method (Método ApplyStyleToParagraph)

O ApplyStyleToParagraph método de exemplo pode ser utilizado para aplicar um estilo a um parágrafo. Primeiro, tem de obter uma referência ao documento, bem como uma referência ao parágrafo que pretende modelar. O método aceita quatro parâmetros que indicam: o caminho para o documento de processamento de palavras a abrir, o styleid do estilo a aplicar, o nome do estilo a aplicar e a referência ao parágrafo ao qual pretende aplicar o estilo.

static void ApplyStyleToParagraph(WordprocessingDocument doc, string styleid, string stylename, Paragraph p)

As secções seguintes neste tópico explicam a implementação deste método e o código de suporte, bem como como chamá-lo. A listagem de código de exemplo completa pode ser encontrada na secção Código de Exemplo no final deste tópico.

Obter um objeto WordprocessingDocument

A secção Código de Exemplo também mostra o código necessário para configurar para chamar o método de exemplo. Para utilizar o método para aplicar um estilo a um parágrafo num documento, primeiro precisa de uma referência ao documento aberto. No SDK Open XML, a WordprocessingDocument classe representa um pacote de documento Word. Para abrir e trabalhar com um Word documento, crie uma instância da classe a WordprocessingDocument partir do documento. Depois de criar a instância, utilize-a para obter acesso à main parte do documento que contém o texto do documento. O conteúdo na parte do documento main é representado no pacote como XML através da marcação WordprocessingML.

Para criar a instância de classe, chame uma das sobrecargas do Open método . O código de exemplo seguinte mostra como utilizar a DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open(String, Boolean) sobrecarga. O primeiro parâmetro aceita uma cadeia de caracteres que representa o caminho completo para o documento a ser aberto. O segundo parâmetro utiliza um valor de true ou false e representa se pretende abrir o ficheiro para edição. Neste exemplo, o parâmetro é true ativar o acesso de leitura/escrita ao ficheiro.

using (WordprocessingDocument doc = WordprocessingDocument.Open(args[0], true))

Estrutura de um Documento wordProcessingML

A estrutura de documentos básica de um WordProcessingML documento consiste nos document elementos e body , seguidos por um ou mais elementos de nível de bloco, como p, que representa um parágrafo. Um parágrafo contém um ou mais r elementos. Significa r execução, que é uma região de texto com um conjunto comum de propriedades, como formatação. Uma execução contém um ou mais t elementos. O t elemento contém um intervalo de texto. O seguinte exemplo de código mostra a WordprocessingML marcação de um documento que contém o texto "Texto de exemplo".

    <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>

Com o SDK Open XML, pode criar estrutura e conteúdo de documentos com classes com tipos fortes que correspondem a WordprocessingML elementos. Encontrará estas classes no espaço de nomes. A tabela seguinte lista os nomes das classes que correspondem aos documentelementos , body, p, re t .

WordprocessingML Element Abrir Classe SDK XML Descrição
<document/> Document O elemento raiz para a parte do documento principal.
<body/> Body O contentor para as estruturas de nível de bloco, como parágrafos, tabelas, anotações e outros especificados na especificação ISO/IEC 29500 .
<p/> Paragraph Um parágrafo.
<r/> Run Uma execução.
<t/> Text Um intervalo de texto.

Para obter mais informações sobre a estrutura geral das partes e elementos de um documento do WordprocessingML, veja Structure of a WordprocessingML document (Estrutura de um documento wordprocessingML).

Colocar o parágrafo no estilo

Depois de abrir o ficheiro, o código de exemplo obtém uma referência ao primeiro parágrafo. Uma vez que um corpo típico do documento de processamento de palavras contém muitos tipos de elementos, o código filtra os descendentes no corpo do documento para os do tipo Paragraph. Em ElementAtOrDefault seguida, o método é utilizado para obter uma referência ao parágrafo. Uma vez que os elementos são indexados a partir de zero, passa um zero para obter a referência ao primeiro parágrafo, conforme mostrado no exemplo de código seguinte.

// Get the first paragraph in the document.
Paragraph? paragraph = doc?.MainDocumentPart?.Document?.Body?.Descendants<Paragraph>().ElementAtOrDefault(0);

A referência ao parágrafo encontrado é armazenada numa variável com o nome parágrafo. Se não for encontrado um parágrafo no índice especificado, o ElementAtOrDefault método devolve nulo como o valor predefinido. Isto proporciona uma oportunidade para testar nulo e gerar um erro com uma mensagem de erro adequada.

Assim que tiver as referências ao documento e ao parágrafo, pode chamar o ApplyStyleToParagraph método de exemplo para fazer o trabalho restante. Para chamar o método , transmita a referência ao documento como o primeiro parâmetro, o styleid do estilo a aplicar como segundo parâmetro, o nome do estilo como o terceiro parâmetro e a referência ao parágrafo ao qual pretende aplicar o estilo, como o quarto parâmetro.

Adicionar o elemento de propriedades de parágrafo

O primeiro passo do método de exemplo é garantir que o parágrafo tem um elemento de propriedades de parágrafo. O elemento de propriedades de parágrafo é um elemento subordinado do parágrafo e inclui um conjunto de propriedades que lhe permite especificar a formatação do parágrafo.

As seguintes informações da especificação ISO/IEC 29500 introduzem o pPr elemento (propriedades de parágrafo) utilizado para especificar a formatação de um parágrafo. Tenha em atenção que os números de secção precedidos por % são da especificação ISO.

No parágrafo, toda a formatação avançada ao nível do parágrafo é armazenada no pPr elemento (\17.3.1.25; \17.3.1.26). [Nota: alguns exemplos de propriedades de parágrafo são alinhamento, limite, substituição de hifenização, avanço, espaçamento entre linhas, sombreado, direção do texto e controlo viúvo/órfão.

Entre as propriedades está o pStyle elemento para especificar o estilo a aplicar ao parágrafo. Por exemplo, a seguinte marcação de exemplo mostra um elemento pStyle que especifica o estilo "OverdueAmount".

    <w:p  xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:pPr>
        <w:pStyle w:val="OverdueAmount" />
      </w:pPr>
      ... 
    </w:p>

No SDK Open XML, o pPr elemento é representado pela ParagraphProperties classe . O código determina se o elemento existe e cria uma nova instância da ParagraphProperties classe se não existir. O pPr elemento é subordinado do p elemento (parágrafo). Consequentemente, o PrependChild método é utilizado para adicionar a instância, conforme mostrado no seguinte exemplo de código.

// If the paragraph has no ParagraphProperties object, create one.
if (p.Elements<ParagraphProperties>().Count() == 0)
{
    p.PrependChild<ParagraphProperties>(new ParagraphProperties());
}

// Get the paragraph properties element of the paragraph.
ParagraphProperties pPr = p.Elements<ParagraphProperties>().First();

Adicionar a parte Estilos

Com o parágrafo encontrado e o elemento de propriedades do parágrafo presentes, certifique-se agora de que os pré-requisitos estão implementados para aplicar o estilo. Os estilos no WordprocessingML são armazenados na sua própria parte exclusiva. Embora normalmente seja verdade que a parte, bem como um conjunto de estilos base, são criados automaticamente quando cria o documento através de uma aplicação como a Microsoft Word, a parte de estilos não é necessária para que um documento seja considerado válido. Se criar o documento através de programação com o SDK Open XML, a parte de estilos não é criada automaticamente; tem de criá-la explicitamente. Consequentemente, o código seguinte verifica se a parte de estilos existe e cria-a se não existir.

// Get the Styles part for this document.
StyleDefinitionsPart? part = doc.MainDocumentPart?.StyleDefinitionsPart;

// If the Styles part does not exist, add it and then add the style.
if (part is null)
{
    part = AddStylesPartToPackage(doc);

O AddStylesPartToPackage método de exemplo faz o trabalho de adicionar a parte estilos. Cria uma parte do tipo, adicionando-a StyleDefinitionsPart como subordinada à parte do documento main. Em seguida, o código acrescenta o Styles elemento raiz, que é o elemento principal que contém todos os estilos. O Styles elemento é representado pela Styles classe no SDK Open XML. Por fim, o código guarda a peça.

// Add a StylesDefinitionsPart to the document.  Returns a reference to it.
static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument doc)
{
    MainDocumentPart mainDocumentPart = doc.MainDocumentPart ?? doc.AddMainDocumentPart();
    StyleDefinitionsPart part = mainDocumentPart.AddNewPart<StyleDefinitionsPart>();
    Styles root = new Styles();

    return part;
}

Verifique se o estilo existe

A aplicação de um estilo que não existe a um parágrafo não tem efeito; não existe nenhuma exceção gerada e não ocorrem alterações de formatação. O código de exemplo verifica se o estilo existe antes de tentar aplicar o estilo. Os estilos são armazenados na parte estilos, pelo que, se a parte de estilos não existir, o estilo em si não pode existir.

Se a parte de estilos existir, o código verifica um estilo correspondente ao chamar o IsStyleIdInDocument método de exemplo e ao transmitir o documento e o styleid. Se não for encontrada nenhuma correspondência no styleid, o código tenta procurar o styleid ao chamar o GetStyleIdFromStyleName método de exemplo e ao transmitir-lhe o nome do estilo.

Se o estilo não existir, quer porque a parte de estilos não existia, quer porque a parte de estilos existe, mas o estilo não existe, o código chama o AddNewStyle método de exemplo para adicionar o estilo.


// Get the Styles part for this document.
StyleDefinitionsPart? part = doc.MainDocumentPart?.StyleDefinitionsPart;

// If the Styles part does not exist, add it and then add the style.
if (part is null)
{
    part = AddStylesPartToPackage(doc);
    AddNewStyle(part, styleid, stylename);
}
else
{
    // If the style is not in the document, add it.
    if (IsStyleIdInDocument(doc, styleid) != true)
    {
        // No match on styleid, so let's try style name.
        string? styleidFromName = GetStyleIdFromStyleName(doc, stylename);

        if (styleidFromName is null)
        {
            AddNewStyle(part, styleid, stylename);
        }
        else
            styleid = styleidFromName;
    }
}

IsStyleInDocument No método de exemplo, o trabalho começa por obter o Styles elemento através Styles da propriedade da StyleDefinitionsPart parte do documento main e, em seguida, determinar se existem estilos como subordinados desse elemento. Todos os elementos de estilo são armazenados como elementos subordinados do elemento de estilos.

Se existirem estilos, o código procura uma correspondência no styleid. O styleid é um atributo do estilo que é utilizado em muitos locais do documento para se referir ao estilo e pode ser considerado como o seu identificador principal. Normalmente, utiliza o styleid para identificar um estilo no código. O FirstOrDefault método é predefinido como nulo se não for encontrada nenhuma correspondência, pelo que o código verifica se foi nulo para ver se um estilo foi correspondido, conforme mostrado no seguinte excerto.

// Return true if the style id is in the document, false otherwise.
static bool IsStyleIdInDocument(WordprocessingDocument doc, string styleid)
{
    // Get access to the Styles element for this document.
    Styles? s = doc.MainDocumentPart?.StyleDefinitionsPart?.Styles;

    if (s is null)
    {
        return false;
    }

    // Check that there are styles and how many.
    int n = s.Elements<Style>().Count();

    if (n == 0)
    {
        return false;
    }

    // Look for a match on styleid.
    Style? style = s.Elements<Style>()
        .Where(st => (st.StyleId is not null && st.StyleId == styleid) && (st.Type is not null && st.Type == StyleValues.Paragraph))
        .FirstOrDefault();
    if (style is null)
    {
        return false;
    }

    return true;
}

Quando não é possível localizar o estilo com base no styleid, o código tenta encontrar uma correspondência com base no nome do estilo. O GetStyleIdFromStyleName método de exemplo funciona, procurando uma correspondência no nome do estilo e devolvendo o styleid do elemento correspondente, se for encontrado, ou nulo, se não for.

Adicionar o estilo à parte estilos

O AddNewStyle método de exemplo utiliza três parâmetros. O primeiro parâmetro faz uma referência à parte estilos. O segundo parâmetro utiliza o styleid do estilo e o terceiro parâmetro utiliza o nome do estilo. O AddNewStyle código cria a definição de estilo com nome na parte especificada.

Para criar o estilo, o código instancia a Style classe e define determinadas propriedades, como o Type estilo (parágrafo) e StyleId. Conforme mencionado acima, o styleid é utilizado pelo documento para se referir ao estilo e pode ser considerado como o identificador principal. Normalmente, utiliza o styleid para identificar um estilo no código. Um estilo também pode ter um nome de estilo amigável de utilizador separado para ser mostrado na interface de utilizador. Muitas vezes, o nome do estilo é apresentado em maiúsculas e minúsculas e com espaçamento (por exemplo, Cabeçalho 1), enquanto o styleid é mais sucinta (por exemplo, cabeçalho1) e destina-se a utilização interna. No código de exemplo seguinte, o styleid e o nome do estilo tiram os respetivos valores dos parâmetros styleid e stylename.

O passo seguinte consiste em especificar algumas propriedades adicionais, como o estilo no qual se baseia o novo estilo e o estilo a aplicar automaticamente ao parágrafo seguinte. O código especifica ambos como o estilo "Normal". Tenha em atenção que o valor a especificar aqui é o styleid do estilo normal. O código acrescenta estas propriedades como subordinados do elemento de estilo.

Assim que o código terminar de instanciar o estilo e configurar as propriedades básicas, agora trabalhe na formatação de estilo. A formatação de estilo é executada nos elementos de propriedades de parágrafo (pPr) e propriedades de execução (rPr). Para definir o tipo de letra e as características de cor das execuções num parágrafo, utilize as propriedades de execução.

Para criar o rPr elemento com os elementos subordinados adequados, o código cria uma instância da StyleRunProperties classe e, em seguida, acrescenta instâncias das classes de propriedade adequadas. Para este exemplo de código, o estilo especifica o tipo de letra Da Consola Lucida, um tamanho de ponto de 12, composto a negrito e itálico, utilizando a cor Destaque2 da parte do tema do documento. O tamanho do ponto é especificado em metade dos pontos, pelo que um valor de 24 é equivalente a 12 pontos.

Quando a definição de estilo estiver concluída, o código acrescenta o estilo ao elemento estilos na parte estilos, conforme mostrado no exemplo de código seguinte.

// Create a new style with the specified styleid and stylename and add it to the specified
// style definitions part.
static void AddNewStyle(StyleDefinitionsPart styleDefinitionsPart, string styleid, string stylename)
{
    // Get access to the root element of the styles part.
    styleDefinitionsPart.Styles ??= new Styles();
    Styles styles = styleDefinitionsPart.Styles;

    // Create a new paragraph style and specify some of the properties.
    Style style = new Style()
    {
        Type = StyleValues.Paragraph,
        StyleId = styleid,
        CustomStyle = true
    };
    StyleName styleName1 = new StyleName() { Val = stylename };
    BasedOn basedOn1 = new BasedOn() { Val = "Normal" };
    NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "Normal" };
    style.Append(styleName1);
    style.Append(basedOn1);
    style.Append(nextParagraphStyle1);

    // Create the StyleRunProperties object and specify some of the run properties.
    StyleRunProperties styleRunProperties1 = new StyleRunProperties();
    Bold bold1 = new Bold();
    Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 };
    RunFonts font1 = new RunFonts() { Ascii = "Lucida Console" };
    Italic italic1 = new Italic();
    // Specify a 12 point size.
    FontSize fontSize1 = new FontSize() { Val = "24" };
    styleRunProperties1.Append(bold1);
    styleRunProperties1.Append(color1);
    styleRunProperties1.Append(font1);
    styleRunProperties1.Append(fontSize1);
    styleRunProperties1.Append(italic1);

    // Add the run properties to the style.
    style.Append(styleRunProperties1);

    // Add the style to the styles part.
    styles.Append(style);
}

Código de exemplo

A seguir está um exemplo de código completo em C# e Visual Basic.

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Linq;

using (WordprocessingDocument doc = WordprocessingDocument.Open(args[0], true))
{
    // Get the first paragraph in the document.
    Paragraph? paragraph = doc?.MainDocumentPart?.Document?.Body?.Descendants<Paragraph>().ElementAtOrDefault(0);

    if (paragraph is not null)
    {
        ApplyStyleToParagraph(doc!, "MyStyle", "MyStyleName", paragraph);
    }
}


// Apply a style to a paragraph.
static void ApplyStyleToParagraph(WordprocessingDocument doc, string styleid, string stylename, Paragraph p)
{
    if (doc is null)
    {
        throw new ArgumentNullException(nameof(doc));
    }

    // If the paragraph has no ParagraphProperties object, create one.
    if (p.Elements<ParagraphProperties>().Count() == 0)
    {
        p.PrependChild<ParagraphProperties>(new ParagraphProperties());
    }

    // Get the paragraph properties element of the paragraph.
    ParagraphProperties pPr = p.Elements<ParagraphProperties>().First();


    // Get the Styles part for this document.
    StyleDefinitionsPart? part = doc.MainDocumentPart?.StyleDefinitionsPart;

    // If the Styles part does not exist, add it and then add the style.
    if (part is null)
    {
        part = AddStylesPartToPackage(doc);
        AddNewStyle(part, styleid, stylename);
    }
    else
    {
        // If the style is not in the document, add it.
        if (IsStyleIdInDocument(doc, styleid) != true)
        {
            // No match on styleid, so let's try style name.
            string? styleidFromName = GetStyleIdFromStyleName(doc, stylename);

            if (styleidFromName is null)
            {
                AddNewStyle(part, styleid, stylename);
            }
            else
                styleid = styleidFromName;
        }
    }

    // Set the style of the paragraph.
    pPr.ParagraphStyleId = new ParagraphStyleId() { Val = styleid };
}

// Return true if the style id is in the document, false otherwise.
static bool IsStyleIdInDocument(WordprocessingDocument doc, string styleid)
{
    // Get access to the Styles element for this document.
    Styles? s = doc.MainDocumentPart?.StyleDefinitionsPart?.Styles;

    if (s is null)
    {
        return false;
    }

    // Check that there are styles and how many.
    int n = s.Elements<Style>().Count();

    if (n == 0)
    {
        return false;
    }

    // Look for a match on styleid.
    Style? style = s.Elements<Style>()
        .Where(st => (st.StyleId is not null && st.StyleId == styleid) && (st.Type is not null && st.Type == StyleValues.Paragraph))
        .FirstOrDefault();
    if (style is null)
    {
        return false;
    }

    return true;
}

// Return styleid that matches the styleName, or null when there's no match.
static string? GetStyleIdFromStyleName(WordprocessingDocument doc, string styleName)
{
    StyleDefinitionsPart? stylePart = doc.MainDocumentPart?.StyleDefinitionsPart;
    string? styleId = stylePart?.Styles?.Descendants<StyleName>()
        .Where(s =>
        {
            OpenXmlElement? p = s.Parent;
            EnumValue<StyleValues>? styleValue = p is null ? null : ((Style)p).Type;

            return s.Val is not null && s.Val.Value is not null && s.Val.Value.Equals(styleName) &&
            (styleValue is not null && styleValue == StyleValues.Paragraph);
        })
        .Select(n =>
        {

            OpenXmlElement? p = n.Parent;
            return p is null ? null : ((Style)p).StyleId;
        }).FirstOrDefault();

    return styleId;
}

// Create a new style with the specified styleid and stylename and add it to the specified
// style definitions part.
static void AddNewStyle(StyleDefinitionsPart styleDefinitionsPart, string styleid, string stylename)
{
    // Get access to the root element of the styles part.
    styleDefinitionsPart.Styles ??= new Styles();
    Styles styles = styleDefinitionsPart.Styles;

    // Create a new paragraph style and specify some of the properties.
    Style style = new Style()
    {
        Type = StyleValues.Paragraph,
        StyleId = styleid,
        CustomStyle = true
    };
    StyleName styleName1 = new StyleName() { Val = stylename };
    BasedOn basedOn1 = new BasedOn() { Val = "Normal" };
    NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "Normal" };
    style.Append(styleName1);
    style.Append(basedOn1);
    style.Append(nextParagraphStyle1);

    // Create the StyleRunProperties object and specify some of the run properties.
    StyleRunProperties styleRunProperties1 = new StyleRunProperties();
    Bold bold1 = new Bold();
    Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 };
    RunFonts font1 = new RunFonts() { Ascii = "Lucida Console" };
    Italic italic1 = new Italic();
    // Specify a 12 point size.
    FontSize fontSize1 = new FontSize() { Val = "24" };
    styleRunProperties1.Append(bold1);
    styleRunProperties1.Append(color1);
    styleRunProperties1.Append(font1);
    styleRunProperties1.Append(fontSize1);
    styleRunProperties1.Append(italic1);

    // Add the run properties to the style.
    style.Append(styleRunProperties1);

    // Add the style to the styles part.
    styles.Append(style);
}

// Add a StylesDefinitionsPart to the document.  Returns a reference to it.
static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument doc)
{
    MainDocumentPart mainDocumentPart = doc.MainDocumentPart ?? doc.AddMainDocumentPart();
    StyleDefinitionsPart part = mainDocumentPart.AddNewPart<StyleDefinitionsPart>();
    Styles root = new Styles();

    return part;
}