Compartilhar via


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

Este tópico mostra como usar as classes no SDK Open XML para Office para aplicar programaticamente um estilo a um parágrafo dentro de um documento de processamento de palavras. Ele contém um método ApplyStyleToParagraph de exemplo para ilustrar essa tarefa, além de vários métodos de exemplo suplementar para marcar se existe um estilo, adicionar um novo estilo e adicionar a parte de estilos.

Método ApplyStyleToParagraph

O método de exemplo ApplyStyleToParagraph pode ser usado para aplicar um estilo a um parágrafo. Primeiro, você deve obter uma referência ao documento, bem como uma referência ao parágrafo que deseja estilizar. O método aceita quatro parâmetros que indicam: a referência ao documento de processamento de palavras abertas, o styleid do estilo a ser aplicado, o nome do estilo a ser aplicado e a referência ao parágrafo ao qual aplicar o estilo.

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

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

Obter um objeto WordprocessingDocument

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

Para criar a instância de classe, chame uma das sobrecargas do método Open(). O código de exemplo a seguir mostra como usar a sobrecarga WordprocessingDocument.Open . O primeiro parâmetro aceita uma cadeia de caracteres que representa o caminho completo para o documento a ser aberto. O segundo parâmetro usa um valor de true ou false e representa se deve abrir o arquivo para edição. Neste exemplo, o parâmetro é verdadeiro para habilitar o acesso de leitura/gravação ao arquivo.

    using (WordprocessingDocument doc = 
        WordprocessingDocument.Open(fileName, true))
    {
       // Code removed here. 
    }

Estrutura de um documento WordProcessingML

A estrutura básica do documento de um documento WordProcessingML consiste nos elementos do documento e do corpo , 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 elementos r . O r significa run, que é uma região de texto com um conjunto comum de propriedades, como a formatação. Uma execução contém um ou mais elementos t . O elemento t contém um intervalo de texto. O exemplo de código a seguir mostra a marcação WordprocessingML para um documento que contém o texto "Texto de exemplo".

    <w:document xmlns:w="https://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>

Usando o SDK do Open XML, você pode criar estrutura de documentos e conteúdo usando classes fortemente tipdas que correspondem aos elementos WordprocessingML . Você encontrará essas classes no namespace DocumentFormat.OpenXml.Wordprocessing . A tabela a seguir lista os nomes de classe das classes que correspondem aos elementos documento, corpo, p, r e t .

Elemento WordprocessingML Classe SDK Open XML Descrição
document Document O elemento raiz para a parte do documento principal.
corpo Body O contêiner 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 WordprocessingML, consulte Estrutura de um documento WordprocessingML.

Obter o parágrafo para o estilo

Depois de abrir o arquivo, o código de exemplo recupera uma referência ao primeiro parágrafo. Como 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 Parágrafo. O método ElementAtOrDefault é então empregado para recuperar uma referência ao parágrafo. Como os elementos são indexados a partir de zero, você passa um zero para recuperar a referência ao primeiro parágrafo, conforme mostrado no exemplo de código a seguir.

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

    // Check for a null reference. 
    if (p == null)
    {
        // Code removed here…
    }

A referência ao parágrafo encontrado é armazenada em uma variável chamada p. Se um parágrafo não for encontrado no índice especificado, o método ElementAtOrDefault retornará nulo como o valor padrão. Isso oferece uma oportunidade de testar nulo e lançar um erro com uma mensagem de erro apropriada.

Depois de ter as referências ao documento e ao parágrafo, você pode chamar o método de exemplo ApplyStyleToParagraph para fazer o trabalho restante. Para chamar o método, você passa a referência ao documento como o primeiro parâmetro, o styleid do estilo a ser aplicado como o segundo parâmetro, o nome do estilo como o terceiro parâmetro e a referência ao parágrafo ao qual aplicar o estilo, como o quarto parâmetro.

Adicionar o elemento propriedades do parágrafo

A primeira etapa do método de exemplo é garantir que o parágrafo tenha um elemento de propriedades de parágrafo. O elemento propriedades do parágrafo é um elemento filho do parágrafo e inclui um conjunto de propriedades que permitem especificar a formatação para o parágrafo.

As informações a seguir da especificação ISO/IEC 29500 introduzem o elemento pPr (propriedades do parágrafo) usado para especificar a formatação de um parágrafo. Observe que os números de seção precedidos por § são da especificação ISO.

No parágrafo, toda a formatação avançada no nível do parágrafo é armazenada dentro do elemento pPr (§17.3.1.25; §17.3.1.26). [Observação: alguns exemplos de propriedades de parágrafo são alinhamento, borda, substituição de hifenização, recuo, espaçamento de linha, sombreamento, direção de texto e controle viúva/órfão.

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

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

No SDK Open XML, o elemento pPr é representado pela classe ParagraphProperties . O código determina se o elemento existe e cria uma nova instância da classe ParagraphProperties se ele não existir. O elemento pPr é filho do elemento p (parágrafo) ; consequentemente, o método T>(T) PrependChild< é usado para adicionar a instância, conforme mostrado no exemplo de código a seguir.

    // 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 propriedades do parágrafo presentes, verifique se os pré-requisitos estão em vigor para aplicar o estilo. Os estilos no WordprocessingML são armazenados em sua própria parte exclusiva. Embora normalmente seja verdade que a parte, bem como um conjunto de estilos base, são criados automaticamente quando você cria o documento usando um aplicativo como o Microsoft Word, a parte de estilos não é necessária para que um documento seja considerado válido. Se você criar o documento programaticamente usando o SDK Open XML, a parte de estilos não será criada automaticamente; você deve criá-lo explicitamente. Consequentemente, o código a seguir verifica se a parte de estilos existe e a cria 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 == null)
    {
        part = AddStylesPartToPackage(doc);
        // Code removed here...
    }

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

    // Add a StylesDefinitionsPart to the document.  Returns a reference to it.
    public static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument doc)
    {
        StyleDefinitionsPart part;
        part = doc.MainDocumentPart.AddNewPart<StyleDefinitionsPart>();
        Styles root = new Styles();
        root.Save(part);
        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 há nenhuma exceção gerada e nenhuma alteração de formatação ocorre. O código de exemplo verifica se o estilo existe antes de tentar aplicar o estilo. Os estilos são armazenados na parte estilos, portanto, se a parte de estilos não existir, o estilo em si não poderá existir.

Se a parte de estilos existir, o código verificará um estilo correspondente chamando o método de exemplo IsStyleIdInDocument e passando o documento e o styleid. Se nenhuma correspondência for encontrada no styleid, o código tentará pesquisar o styleid chamando o método de exemplo GetStyleIdFromStyleName e passando-o o nome do estilo.

Se o estilo não existir, porque a parte de estilos não existiu ou porque a parte de estilos existe, mas o estilo não existe, o código chama o método de exemplo AddNewStyle 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 == 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 == null)
            {
                AddNewStyle(part, styleid, stylename);
            }
            else
                styleid = styleidFromName;
        }
    }

No método de exemplo IsStyleInDocument, o trabalho começa com a recuperação do elemento Styles por meio da propriedade Styles do StyleDefinitionsPart da parte do documento main e, em seguida, determinando se existem estilos como filhos desse elemento. Todos os elementos de estilo são armazenados como filhos do elemento styles.

Se os estilos existirem, o código procurará uma correspondência no styleid. O styleid é um atributo do estilo que é usado em muitos lugares no documento para se referir ao estilo e pode ser considerado como seu identificador primário. Normalmente, você usa o styleid para identificar um estilo no código. O método FirstOrDefault padrão será nulo se nenhuma correspondência for encontrada, portanto, o código verificará nulo para ver se um estilo foi correspondido, conforme mostrado no trecho a seguir.

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

        // 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 == styleid) && (st.Type == StyleValues.Paragraph))
            .FirstOrDefault();
        if (style == null)
                return false;
        
        return true;
    }

Quando o estilo não pode ser encontrado com base no styleid, o código tenta encontrar uma correspondência com base no nome do estilo. O método de exemplo GetStyleIdFromStyleName faz esse trabalho, procurando uma correspondência no nome do estilo e retornando o styleid para o elemento correspondente se encontrado ou nulo, se não.

Adicionar o estilo à parte de estilos

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

Para criar o estilo, o código instancia a classe Style e define determinadas propriedades, como o tipo de estilo (parágrafo) e StyleId. Conforme mencionado acima, o styleid é usado pelo documento para se referir ao estilo e pode ser considerado como seu identificador primário. Normalmente, você usa o styleid para identificar um estilo no código. Um estilo também pode ter um nome de estilo amigável ao usuário separado a ser mostrado na interface do usuário. Geralmente, o nome de estilo aparece, portanto, no caso adequado e com espaçamento (por exemplo, Título 1), enquanto o styleid é mais sucinto (por exemplo, título1) e destinado ao uso interno. No código de exemplo a seguir, o nome styleid e style tiram seus valores dos parâmetros styleid e stylename.

A próxima etapa é especificar algumas propriedades adicionais, como o estilo no qual o novo estilo se baseia e o estilo a ser aplicado automaticamente ao próximo parágrafo. O código especifica ambos como o estilo "Normal". Lembre-se de que o valor a ser especificado aqui é o styleid para o estilo normal. O código acrescenta essas propriedades como filhos do elemento de estilo.

Depois que o código terminar de instanciar o estilo e configurar as propriedades básicas, agora funcionará na formatação de estilo. A formatação de estilo é executada nos elementos propriedades de parágrafo (pPr) e propriedades de execução (rPr). Para definir as características de fonte e cor para as execuções em um parágrafo, use as propriedades de execução.

Para criar o elemento rPr com os elementos filho apropriados, o código cria uma instância da classe StyleRunProperties e acrescenta instâncias das classes de propriedade apropriadas. Para este exemplo de código, o estilo especifica a fonte Console do Lucida, um tamanho de ponto de 12, renderizada em negrito e itálico, usando a cor Accent2 da parte do tema do documento. O tamanho do ponto é especificado em meio ponto, portanto, um valor de 24 é equivalente a 12 pontos.

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

    // Create a new style with the specified styleid and stylename and add it to the specified
    // style definitions part.
    private static void AddNewStyle(StyleDefinitionsPart styleDefinitionsPart, 
        string styleid, string stylename)
    {
        // Get access to the root element of the styles part.
        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);
    }

Aplicar o estilo ao parágrafo

Agora, o código de exemplo localizou o parágrafo, adicionou o elemento de propriedades de parágrafo necessário, se necessário, verificou a parte de estilos e adicionou-o, se necessário, e verificou o estilo e adicionou-o, se necessário. Agora, defina o estilo de parágrafo. Para realizar essa tarefa, o código cria uma instância da classe ParagraphStyleId com o styleid e, em seguida, coloca uma referência a essa instância na propriedade ParagraphStyleId do objeto propriedades do parágrafo. Isso cria e atribui o valor apropriado ao elemento pStyle que especifica o estilo a ser usado para o parágrafo.

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

Código de exemplo

Você pode usar o método de exemplo ApplyStyleToParagraph para aplicar um estilo nomeado a um parágrafo em um documento de processamento de palavras usando o SDK Open XML. O código a seguir mostra como abrir e adquirir uma referência a um documento de processamento de palavras, recuperar uma referência ao primeiro parágrafo e, em seguida, chamar o método ApplyStyleToParagraph .

Para chamar o método, passe a referência ao documento como o primeiro parâmetro, o styleid do estilo a ser aplicado como o segundo parâmetro, o nome do estilo como o terceiro parâmetro e a referência ao parágrafo ao qual aplicar o estilo, como o quarto parâmetro. Por exemplo, o código a seguir aplica o estilo "Quantidade Atrasada" ao primeiro parágrafo no arquivo de exemplo chamado ApplyStyleToParagraph.docx.

    string filename = @"C:\Users\Public\Documents\ApplyStyleToParagraph.docx";

    using (WordprocessingDocument doc =
        WordprocessingDocument.Open(filename, true))
    {
        // Get the first paragraph.
        Paragraph p =
          doc.MainDocumentPart.Document.Body.Descendants<Paragraph>()
          .ElementAtOrDefault(1);

        // Check for a null reference. 
        if (p == null)
        {
            throw new ArgumentOutOfRangeException("p", 
                "Paragraph was not found.");
        }

        ApplyStyleToParagraph(doc, "OverdueAmount", "Overdue Amount", p);
    }

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;


// 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();
    root.Save(part);

    return part;
}