Compartir a través de


Aceptar todas las revisiones realizadas en un documento de procesamiento de texto

En este tema se muestra cómo usar el SDK de Open XML para Office para aceptar todas las revisiones de un documento de procesamiento de texto mediante programación.

Estructura de un documento WordProcessingML

La estructura de documento básica de un documento WordProcessingML contiene los elementos document y body, seguidos de uno o varios elementos a nivel de bloque, como p, que representa un párrafo. Un párrafo contiene uno o varios elementos r. La r representa a run (segmento), que es una región de texto con un conjunto de propiedades comunes, como el formato. Un segmento contiene uno o varios elementos t. El elemento t contiene un intervalo de texto. En el siguiente ejemplo de código se muestra el marcado WordprocessingML de un documento que contiene el texto "Example text".

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

Con el SDK de Open XML, puede crear contenido y estructura de documentos mediante clases fuertemente tipadas que corresponden a elementos WordprocessingML . Puede encontrar estas clases en el espacio de nombres DocumentFormat.OpenXml.Wordprocessing . La tabla siguiente muestra los nombres de las clases que corresponden a los elementos document, body, p, r y t.

Elemento de WordprocessingML Open XML SDK (clase) Descripción
documento 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.

La estructura de documento básica de un documento WordProcessingML contiene los elementos document y body, seguidos de uno o varios elementos a nivel de bloque, como p, que representa un párrafo. Un párrafo contiene uno o varios elementos r. La r representa a run (segmento), que es una región de texto con un conjunto de propiedades comunes, como el formato. Un segmento contiene uno o varios elementos t. El elemento t contiene un intervalo de texto. En el siguiente ejemplo de código se muestra el marcado WordprocessingML de un documento que contiene el texto "Example text".

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

Con el SDK de Open XML, puede crear contenido y estructura de documentos mediante clases fuertemente tipadas que corresponden a elementos WordprocessingML . Puede encontrar estas clases en el espacio de nombres DocumentFormat.OpenXml.Wordprocessing . La tabla siguiente muestra los nombres de las clases que corresponden a los elementos document, body, p, r y t.

Elemento de WordprocessingML Open XML SDK (clase) Descripción
documento 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.

Elemento ParagraphPropertiesChange

Cuando acepta una marca de revisión, se cambian las propiedades de un párrafo mediante la eliminación de un texto existente o la inserción de un nuevo texto. En las secciones siguientes, se leen tres elementos que se usan en el código para cambiar el contenido del párrafo, principalmente ( <w: pPrChange\> información de revisión para las propiedades de párrafo), <w:del> (párrafo eliminado) y <w:ins> (fila de tabla insertada).

La siguiente información de la especificación ISO/IEC 29500 presenta el elemento ParagraphPropertiesChange (pPrChange).

*pPrChange (información de revisión para las propiedades de párrafo)

Este elemento especifica los detalles acerca de una única revisión a un conjunto de propiedades de párrafo en un documento WordprocessingML.

Este elemento almacena esta revisión, como se muestra a continuación:

  • El elemento secundario de este elemento contiene el conjunto completo de las propiedades de párrafo que se aplicaron a este párrafo antes de esta revisión.

  • Los atributos de este elemento contienen información acerca de cuándo se realizó esta revisión (es decir, cuándo estas propiedades se convirtieron en un conjunto "anterior" de propiedades de párrafo).

Considere un documento WordprocessingML en el que se centra la alineación de un párrafo y dicho cambio en las propiedades del párrafo se marca como una revisión en el control de cambios. Esta revisión se especificará mediante el siguiente marcado de 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>

El elemento especifica que Samantha Smith realizó una revisión de las propiedades del párrafo el 01-01-2006 y que el conjunto anterior de propiedades del párrafo era el conjunto nulo (es decir, no hay propiedades de párrafo presentes de forma explícita en el elemento). pPrpPrChange

© ISO/IEC29500: 2008.

Elemento de eliminado

La siguiente información de la especificación ISO/IEC 29500 presenta el elemento Deleted (del).

del (párrafo eliminado)

Este elemento especifica que la marca de párrafo que delimita el final de un párrafo de un documento WordprocessingML se debe tratar como eliminada (es decir, el contenido del párrafo ya no está delimitado por la marca de párrafo y se combina con el párrafo siguiente, pero dicho contenido no se marcará automáticamente como eliminado) como parte de la revisión marcada en el control de cambios.

Considere un documento que consta de dos párrafos (con cada párrafo delimitado por un signo de antígrafo ¶):

Dos párrafos cada uno delimitado por un pilcrow Si se elimina el carácter físico que delimita el final del primer párrafo y se realiza un seguimiento de este cambio como revisión, se producirá lo siguiente:

Dos párrafos delimitados por un solo pilcrow Esta revisión se representa mediante el esquema WordprocessingML siguiente:

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

El elemento del de las propiedades de segmento de la primera marca de párrafo especifica que se ha eliminado esta marca de párrafo y que dicha eliminación se marcó como una revisión en el control de cambios.

© ISO/IEC29500: 2008.

Elemento de insertado

La siguiente información de la especificación ISO/IEC 29500 presenta el elemento Inserted (ins).

ins (fila de tabla insertada)

Este elemento especifica que la fila de tabla principal se debe tratar como una fila insertada, cuya inserción se ha marcado como revisión en el control de cambios. Esta opción no implicará ningún estado de revisión para las celdas de tabla de esta fila o su contenido (que se debe marcar como revisión de forma independiente) y solo afectará a la fila de tabla en sí.

Considere una tabla de dos filas y dos columnas en la que la segunda fila se ha marcado como insertada mediante una revisión. Este requisito se especifica mediante el WordprocessingML siguiente:

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

El elemento ins de las propiedades de fila de tabla de la segunda fila de tabla especifica que esta fila se insertó y que dicha inserción se marcó como una revisión en el control de cambios.

© ISO/IEC29500: 2008.

Código de ejemplo

En el siguiente ejemplo de código se muestra cómo aceptar todas las revisiones de un documento de procesamiento de texto. Para ejecutar el programa, puede pasar la ruta de acceso del archivo y el nombre del autor:

dotnet run -- [filePath] [authorName]

Después de ejecutar el programa, abra el archivo de procesamiento de texto para asegurarse de que se han aceptado todas las marcas de revisión.

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