Share via


Insertar un comentario en un documento de procesamiento de texto

En este tema se muestra cómo usar las clases del SDK de Open XML para Office para agregar mediante programación un comentario al primer párrafo de un documento de procesamiento de texto.


Abrir el documento existente para su edición

Para abrir un documento existente, cree una instancia de la clase WordprocessingDocument como se muestra en la siguiente instrucción using. En la misma instrucción, abra el archivo de procesamiento de texto en la ruta de archivo especificada mediante el método Open(String, Boolean), con el parámetro booleano establecido en true para habilitar la edición en el documento.

    using (WordprocessingDocument document =
           WordprocessingDocument.Open(filepath, true)) 
    { 
       // Insert other code here. 
    }

La instrucción using proporciona una alternativa recomendada a la típica secuencia .Open, .Save, .Close. Garantiza que se llamará automáticamente al método Dispose (un método interno que Open XML SDK usa para limpiar recursos) cuando se llegue al corchete de cierre. El bloque que sigue a la instrucción using establece un ámbito para el objeto que se crea o se nombra en la instrucción using, en este caso document.


Funcionamiento del código de ejemplo

Una vez abierto el documento, puede buscar el primer párrafo para adjuntar un comentario. El código busca el primer párrafo llamando al método de extensión First en todos los elementos descendientes del elemento de documento que son de tipo Paragraph. El método First es miembro de la clase System.Linq.Enumerable . La clase System.Linq.Enumerable proporciona métodos de extensión para objetos que implementan la interfaz System.Collections.Generic.IEnumerable .

    Paragraph firstParagraph = document.MainDocumentPart.Document.Descendants<Paragraph>().First();
    Comments comments = null;
    string id = "0";

En primer lugar, el código determina si existe una parte WordprocessingCommentsPart . Para ello, llame al método genérico MainDocumentPart , GetPartsCountOfType, y especifique un tipo de WordprocessingCommentsPart.

Si existe un elemento WordprocessingCommentsPart , el código obtiene un nuevo valor Id para el objeto Comment que agregará al objeto de colección WordprocessingCommentsPartComments existente. Para ello, busca el valor de atributo Id más alto que se proporciona a un comentario en el objeto de colección Comments , incrementa el valor en uno y, a continuación, lo almacena como el valor id . Si no existe ningún elemento WordprocessingCommentsPart , el código crea uno mediante el método AddNewPart<T>() del objeto MainDocumentPart y, a continuación, le agrega un objeto de colección Comments .

    if (document.MainDocumentPart.GetPartsCountOfType<WordprocessingCommentsPart>() > 0)
    {
        comments = 
            document.MainDocumentPart.WordprocessingCommentsPart.Comments;
        if (comments.HasChildren)
        {
            id = (comments.Descendants<Comment>().Select(e => int.Parse(e.Id.Value)).Max() + 1).ToString();
        }
    }
    else
    {
        WordprocessingCommentsPart commentPart = 
                    document.MainDocumentPart.AddNewPart<WordprocessingCommentsPart>();
       commentPart.Comments = new Comments();
       comments = commentPart.Comments;
    }

Los objetos Comment y Comments representan comentarios y elementos de comentarios, respectivamente, en el esquema de procesamiento de texto de Office Open XML. Debe agregarse Comment a un objeto Comments para que el código primero cree una instancia de un objeto Comments (mediante el uso de los argumentos de cadena author, initials y comments que se pasaron al método AddCommentOnFirstParagraph).

El comentario se representa mediante el siguiente ejemplo de código WordprocessingML. .

    <w:comment w:id="1" w:initials="User">
      ...
    </w:comment>

A continuación, el código agrega Comment al objeto Comments y guarda los cambios. Esto crea la estructura necesaria del árbol de DOM (Document Object Model) de XML en la memoria que consta de un elemento comments primario con elementos comment secundarios por debajo.

    Paragraph p = new Paragraph(new Run(new Text(comment)));
    Comment cmt = new Comment() { Id = id, 
            Author = author, Initials = initials, Date = DateTime.Now };
    cmt.AppendChild(p);
    comments.AppendChild(cmt);
    comments.Save();

El siguiente ejemplo de código de WordprocessingML representa el contenido de una parte de comentarios en un documento WordprocessingML.

    <w:comments>
      <w:comment … >
        …
      </w:comment>
    </w:comments>

Una vez creada la instancia del objeto Comment, el código asocia Comment con un intervalo del documento de procesamiento de texto. Los objetos CommentRangeStart y CommentRangeEnd corresponden a los elementos commentRangeStart y commentRangeEnd del esquema Wordprocessing de Open XML. Un objeto CommentRangeStart se asigna como argumento al método InsertBefore<T>(T, OpenXmlElement) del objeto Paragraph y un objeto CommentRangeEnd se pasa al método InsertAfter<T>(T, OpenXmlElement). Esto crea un intervalo de comentarios que se extiende desde antes del primer carácter del primer párrafo del documento de procesamiento de texto hasta después del último carácter del primer párrafo.

Un objeto CommentReference representa una parte commentReference en el esquema de procesamiento de texto de Office Open XML. Una parte commentReference vincula un comentario específico del elemento WordprocessingCommentsPart (el archivo Comments.xml del paquete de procesamiento de texto) a una ubicación específica del cuerpo del documento (el elemento MainDocumentPart que se incluye en el archivo Document.xml del paquete de procesamiento de texto). El atributo id de comment, commentRangeStart, commentRangeEnd y commentReference es el mismo para un comentario determinado, por lo que el atributo id de commentReference debe coincidir con el valor del atributo id de comment vinculado. En el ejemplo, el código agrega un elemento commentReference mediante la API y crea una instancia de un objeto CommentReference , especificando el valor Id y, a continuación, lo agrega a un objeto Run .

    firstParagraph.InsertBefore(new CommentRangeStart() 
                { Id = id }, firstParagraph.GetFirstChild<Run>());

            var cmtEnd = firstParagraph.InsertAfter(new CommentRangeEnd() 
                { Id = id }, firstParagraph.Elements<Run>().Last());

            firstParagraph.InsertAfter(new Run(new CommentReference() { Id = id }), cmtEnd);

Código de ejemplo

En el siguiente ejemplo de código se muestra cómo crear un comentario y cómo asociarlo con un intervalo en un documento de procesamiento de texto. Para llamar al método AddCommentOnFirstParagraph, pase la ruta de acceso del documento, su nombre e iniciales y el texto del comentario. Por ejemplo, la siguiente llamada al método AddCommentOnFirstParagraph escribe el comentario "This is my comment." en el archivo "Word8.docx".

    AddCommentOnFirstParagraph(@"C:\Users\Public\Documents\Word8.docx",
     author, initials, "This is my comment.");

A continuación se incluye el código de ejemplo completo en C# y Visual Basic.

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

AddCommentOnFirstParagraph(args[0], args[1], args[2], args[3]);

// Insert a comment on the first paragraph.
static void AddCommentOnFirstParagraph(string fileName, string author, string initials, string comment)
{
    // Use the file name and path passed in as an 
    // argument to open an existing Wordprocessing document. 
    using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true))
    {
        if (document.MainDocumentPart is null/* || document.MainDocumentPart.WordprocessingCommentsPart is null*/)
        {
            throw new ArgumentNullException("MainDocumentPart and/or Body is null.");
        }

        WordprocessingCommentsPart wordprocessingCommentsPart = document.MainDocumentPart.WordprocessingCommentsPart ?? document.MainDocumentPart.AddNewPart<WordprocessingCommentsPart>();

        // Locate the first paragraph in the document.
        Paragraph firstParagraph = document.MainDocumentPart.Document.Descendants<Paragraph>().First();
        wordprocessingCommentsPart.Comments ??= new Comments();
        string id = "0";

        // Verify that the document contains a 
        // WordProcessingCommentsPart part; if not, add a new one.
        if (document.MainDocumentPart.GetPartsOfType<WordprocessingCommentsPart>().Count() > 0)
        {
            if (wordprocessingCommentsPart.Comments.HasChildren)
            {
                // Obtain an unused ID.
                id = (wordprocessingCommentsPart.Comments.Descendants<Comment>().Select(e =>
                {
                    if (e.Id is not null && e.Id.Value is not null)
                    {
                        return int.Parse(e.Id.Value);
                    }
                    else
                    {
                        throw new ArgumentNullException("Comment id and/or value are null.");
                    }
                })
                    .Max() + 1).ToString();
            }
        }

        // Compose a new Comment and add it to the Comments part.
        Paragraph p = new Paragraph(new Run(new Text(comment)));
        Comment cmt =
            new Comment()
            {
                Id = id,
                Author = author,
                Initials = initials,
                Date = DateTime.Now
            };
        cmt.AppendChild(p);
        wordprocessingCommentsPart.Comments.AppendChild(cmt);
        wordprocessingCommentsPart.Comments.Save();

        // Specify the text range for the Comment. 
        // Insert the new CommentRangeStart before the first run of paragraph.
        firstParagraph.InsertBefore(new CommentRangeStart()
        { Id = id }, firstParagraph.GetFirstChild<Run>());

        // Insert the new CommentRangeEnd after last run of paragraph.
        var cmtEnd = firstParagraph.InsertAfter(new CommentRangeEnd()
        { Id = id }, firstParagraph.Elements<Run>().Last());

        // Compose a run with CommentReference and insert it.
        firstParagraph.InsertAfter(new Run(new CommentReference() { Id = id }), cmtEnd);
    }
}

Vea también

Language-Integrated Query (LINQ)

Métodos de extensión (Guía de programación de C#)

Métodos de extensión (Visual Basic)