Compartir a través de


Aplicar un estilo a un párrafo de un documento de procesamiento de texto

En este tema se muestra cómo usar las clases del SDK de Open XML para Office para aplicar mediante programación un estilo a un párrafo dentro de un documento de procesamiento de texto. Contiene un método de ejemplo ApplyStyleToParagraph para ilustrar esta tarea, además de varios métodos de ejemplo complementarios para comprobar si existe un estilo, agregar un nuevo estilo y agregar la parte styles.

ApplyStyleToParagraph (método)

El ApplyStyleToParagraph método de ejemplo se puede usar para aplicar un estilo a un párrafo. Primero debe obtener una referencia al documento así como una referencia al párrafo al que desee asignar un estilo. El método acepta cuatro parámetros que indican: la ruta de acceso al documento de procesamiento de texto que se va a abrir, el styleid del estilo que se va a aplicar, el nombre del estilo que se va a aplicar y la referencia al párrafo al que se va a aplicar el estilo.

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

En las siguientes secciones de este tema se explica la implementación de este método y el código de apoyo, así como el modo de llamarlo. Encontrará el listado completo de códigos en la sección Código de ejemplo al final de este tema.

Obtención de un objeto WordprocessingDocument

La sección Código de ejemplo también muestra el código que se debe configurar para llamar al método de ejemplo. Para usar el método para aplicar un estilo a un párrafo de un documento, primero necesita una referencia para abrir el documento. En el SDK de Open XML, la WordprocessingDocument clase representa un paquete de documento Word. Para abrir y trabajar con un documento Word, cree una instancia de la WordprocessingDocument clase a partir del documento. Después de crear la instancia, úsela para obtener acceso al elemento de documento principal que contiene el texto del documento. El contenido de la parte del documento principal se representa en el paquete como XML mediante marcado WordprocessingML.

Para crear la instancia de clase, llame a una de las sobrecargas del Open método . En el código de ejemplo siguiente se muestra cómo usar la DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open(String, Boolean) sobrecarga. El primer parámetro toma una cadena que representa la ruta de acceso completa al documento que se va a abrir. El segundo parámetro toma un valor de true o false y representa si se va a abrir el archivo para su edición. En este ejemplo, el parámetro es true habilitar el acceso de lectura y escritura al archivo.

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

Estructura de un documento WordProcessingML

La estructura básica de un WordProcessingML documento consta de los document elementos y body , seguidos de uno o varios elementos de nivel de bloque, como p, que representa un párrafo. Un párrafo contiene uno o varios r elementos. significa r ejecutar, que es una región de texto con un conjunto común de propiedades, como el formato. Una ejecución contiene uno o varios t elementos. El t elemento contiene un intervalo de texto. En el ejemplo de código siguiente se muestra el WordprocessingML marcado de un documento que contiene el texto "Texto de ejemplo".

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

Con el SDK de Open XML, puede crear contenido y estructura de documentos mediante clases fuertemente tipadas que corresponden a WordprocessingML elementos. Encontrará estas clases en el espacio de DocumentFormat.OpenXml.Wordprocessing nombres. En la tabla siguiente se enumeran los nombres de clase de las clases correspondientes a los documentelementos , body, p, ry t .

Elemento de WordprocessingML Open XML SDK (clase) Descripción
<document/> Document El elemento raíz del elemento de documento principal.
<body/> Body El contenedor de las estructuras a nivel de bloque, como párrafos, tablas, anotaciones y otras recogidas en la especificación ISO/IEC 29500.
<p/> Paragraph Un párrafo.
<r/> Run Un segmento.
<t/> Text Un intervalo de texto.

Para obtener más información sobre la estructura general de los elementos y elementos de un documento WordprocessingML, vea Estructura de un documento WordprocessingML.

Obtener el estilo del párrafo

Tras abrir el archivo, el código de ejemplo recupera una referencia al primer párrafo. Dado que un cuerpo de documento de procesamiento de texto típico contiene muchos tipos de elementos, el código filtra los descendientes del cuerpo del documento a los del tipo Paragraph. A ElementAtOrDefault continuación, se emplea el método para recuperar una referencia al párrafo. Puesto que los elementos están indizados para que empiecen de cero, debe pasar un cero para recuperar la referencia al primer párrafo, tal como se muestra en el siguiente ejemplo de código.

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

La referencia al párrafo encontrado se almacena en una variable denominada paragraph. Si no se encuentra un párrafo en el índice especificado, el ElementAtOrDefault método devuelve null como valor predeterminado. Esto proporciona una oportunidad para probar el valor null y lanzar un error con un mensaje de error apropiado.

Una vez que tenga las referencias al documento y al párrafo, puede llamar al método de ApplyStyleToParagraph ejemplo para realizar el trabajo restante. Para llamar al método, debe pasar la referencia al documento como primer parámetro, el styleid del estilo que desee aplicar como segundo parámetro, el nombre del estilo como tercer parámetro y la referencia al párrafo al que desee aplicar el estilo como cuarto parámetro.

Agregar el elemento de propiedades de párrafo

El primer paso del método de ejemplo es asegurarse de que el párrafo tenga un elemento propiedades del párrafo. El elemento propiedades del párrafo es un elemento secundario del párrafo e incluye un conjunto de propiedades que le permiten especificar el formato del párrafo.

La siguiente información de la especificación ISO/IEC 29500 presenta el pPr elemento (propiedades de párrafo) que se usa para especificar el formato de un párrafo. Tenga en cuenta que los números de sección precedidos de § son de la especificación ISO.

Dentro del párrafo, todo el formato enriquecido en el nivel de párrafo se almacena en el pPr elemento (§17.3.1.25; §17.3.1.26). [Nota: algunos ejemplos de propiedades del párrafo son alineación, borde, invalidación de guiones, sangría, interlineado, sombreado, dirección del texto y control viudo/huérfano.

Entre las propiedades se encuentra el pStyle elemento para especificar el estilo que se va a aplicar al párrafo. Por ejemplo, el siguiente marcado de ejemplo muestra un elemento pStyle que especifica el estilo "OverdueAmount".

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

En el SDK de Open XML, el pPr elemento se representa mediante la ParagraphProperties clase . El código determina si el elemento existe y crea una nueva instancia de la ParagraphProperties clase si no lo hace. El pPr elemento es un elemento secundario del p elemento (párrafo); por lo tanto, el PrependChild método se usa para agregar la instancia, como se muestra en el ejemplo de código siguiente.

// 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();

Agregar la parte Estilos

Una vez encontrado el párrafo y teniendo el elemento propiedades del párrafo, asegúrese de cumplir con los requisitos previos para aplicar el estilo. Los estilos en WordprocessingML se almacenan en su propia parte única. Aunque generalmente es cierto que la parte así como un conjunto de estilos base se crean automáticamente al crear el documento mediante una aplicación como Microsoft Word, la parte styles no es necesaria para que un documento se considere válido. Si crea el documento mediante programación usando el SDK de Open XML, la parte styles no se crea automáticamente; debe crearla explícitamente. Por lo tanto, el siguiente código comprueba que existe la parte styles y la crea si no existe.

// 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);

El AddStylesPartToPackage método de ejemplo realiza el trabajo de agregar la parte styles. Crea una parte del StyleDefinitionsPart tipo y la agrega como elemento secundario a la parte principal del documento. A continuación, el código anexa el Styles elemento raíz, que es el elemento primario que contiene todos los estilos. El Styles elemento se representa mediante la Styles clase en el SDK de Open XML. Por último, el código guarda la parte.

// 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;
}

Comprobar que el estilo existe

La aplicación de un estilo que no existe a un párrafo no tiene ningún efecto; no se genera ninguna excepción y no se produce ningún cambio de formato. El código de ejemplo comprueba que el estilo exista antes de intentar aplicarlo. Los estilos se almacenan en la parte styles, por lo que si la parte styles no existe, el estilo en si no puede existir.

Si la parte styles existe, el código comprueba un estilo coincidente llamando al método de IsStyleIdInDocument ejemplo y pasando el documento y el styleid. Si no se encuentra ninguna coincidencia en styleid, el código intenta buscar el styleid llamando al GetStyleIdFromStyleName método de ejemplo y pasándole el nombre del estilo.

Si el estilo no existe, ya sea porque la parte styles no existía o porque la parte styles existe, pero el estilo no, el código llama al AddNewStyle método de ejemplo para agregar el 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;
    }
}

Dentro del IsStyleInDocument método de ejemplo, el trabajo comienza con la recuperación del Styles elemento a través de la Styles propiedad del StyleDefinitionsPart elemento del documento principal y, a continuación, determinar si existen estilos como elementos secundarios de ese elemento. Todos los elementos de estilo se almacenan como elementos secundarios del elemento styles.

Si los estilos no existen, el código busca una coincidencia en el styleid. El styleid es un atributo del estilo que se usa en muchos sitios del documento para referirse al estilo y puede considerarse como su identificador principal. Generalmente se usa el styleid para identificar un estilo en código. El FirstOrDefault método tiene como valor predeterminado null si no se encuentra ninguna coincidencia, por lo que el código comprueba si es null para ver si se ha coincidente un estilo, como se muestra en el siguiente extracto.

// 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;
}

Cuando no se encuentra el estilo basándose en el styleid, el código intenta encontrar una coincidencia basándose en el nombre del estilo. El GetStyleIdFromStyleName método de ejemplo realiza este trabajo, buscando una coincidencia en el nombre del estilo y devolviendo el styleid para el elemento coincidente si se encuentra, o null si no.

Agregar el estilo a la parte styles

El AddNewStyle método de ejemplo toma tres parámetros. El primer parámetro toma una referencia a la parte styles. El segundo parámetro toma el styleid del estilo y el tercer parámetro toma el nombre del estilo. El AddNewStyle código crea la definición de estilo con nombre dentro de la parte especificada.

Para crear el estilo, el código crea una instancia de la Style clase y establece ciertas propiedades, como el Type de estilo (párrafo) y StyleId. Como se mencionaba anteriormente, el documento usa el styleid para referirse al estilo, y se puede considerar su identificador principal. Generalmente se usa el styleid para identificar un estilo en código. Un estilo también puede tener un nombre de estilo descriptivo e independiente para que aparezca en la interfaz de usuario. A menudo, por lo tanto, el nombre de estilo aparece en mayúsculas o minúsculas, según corresponda, con espacio (por ejemplo, Encabezado 1), mientras que el styleid es más sucinto (por ejemplo, encabezado1) y pensado para uso interno. En el siguiente código de ejemplo, el styleid y el nombre de estilo toman sus valores a partir de los parámetros styleid y stylename.

El siguiente paso es especificar unas cuantas propiedades adicionales, como el estilo en el que se basa el nuevo estilo y el estilo que se debe aplicar automáticamente al siguiente párrafo. El código especifica ambos como estilo "Normal". Tenga en cuenta que el valor que se debe especificar aquí es el styleid del estilo normal. El código anexa estas propiedades como elementos secundarios del elemento de estilo.

Una vez que el código haya terminado de crear la instancia del estilo y configurar las propiedades básicas, trabaje sobre el formato del estilo. El formato de estilo se realiza en los elementos de propiedades de párrafo (pPr) y propiedades de ejecución (rPr). Para establecer las características de fuente y color para los segmentos de un párrafo, use las propiedades del segmento.

Para crear el rPr elemento con los elementos secundarios adecuados, el código crea una instancia de la StyleRunProperties clase y, a continuación, anexa instancias de las clases de propiedad adecuadas. Para este ejemplo de código, el estilo especifica la fuente Lucida Console, un tamaño 12, representado en negrita y cursiva, con el color Accent2 de la parte del tema del documento. El tamaño se especifica en medios puntos, de modo que un valor 24 es equivalente a 12 puntos.

Una vez completada la definición de estilo, el código anexa el estilo o el elemento styles a la parte styles, como se muestra en el siguiente ejemplo de código.

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

A continuación se muestra el ejemplo de código completo en C# y 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;
}