Compartilhar via


Inserir um comentário em um documento de processamento de texto

Este tópico mostra como utilizar as classes no SDK Open XML para o Office para adicionar programaticamente um comentário ao primeiro parágrafo num documento de processamento de palavras.


Abrir o Documento Existente para Edição

Para abrir um documento existente, instanciar a WordprocessingDocument classe conforme mostrado na seguinte using instrução. Na mesma instrução, abra o ficheiro de processamento de palavras no caminho de ficheiro especificado com o Open(String, Boolean) método , com o parâmetro Booleano definido para true ativar a edição no documento.

using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true))

Com a v3.0.0+ o Close() método foi removido a favor de depender da instrução using. Garante que o Dispose() método é chamado automaticamente quando a chaveta de fecho é atingida. O bloco que segue a instrução using estabelece um âmbito para o objeto que é criado ou nomeado na instrução using. Uma vez que a WordprocessingDocument classe no SDK Open XML guarda e fecha automaticamente o objeto como parte da respetiva IDisposable implementação e porque Dispose() é automaticamente chamada quando sai do bloco, não tem de chamar Save() explicitamente ou Dispose() desde que utilize uma using instrução.


Como funciona o código de exemplo

Depois de abrir o documento, pode encontrar o primeiro parágrafo para anexar um comentário. O código localiza o primeiro parágrafo ao chamar o First método de extensão em todos os elementos descendentes do elemento do documento que são do tipo Paragraph. O First método é um membro da Enumerable classe . A System.Linq.Enumerable classe fornece métodos de extensão para objetos que implementam a IEnumerable<T> interface.

Paragraph firstParagraph = document.MainDocumentPart.Document.Descendants<Paragraph>().First();
wordprocessingCommentsPart.Comments ??= new Comments();
string id = "0";

Primeiro, o código determina se existe uma WordprocessingCommentsPart parte. Para tal, chame o MainDocumentPart método genérico e GetPartsCountOfTypeespecifique um tipo de WordprocessingCommentsPart.

Se existir uma WordprocessingCommentsPart parte, o código obtém um novo Id valor para o Comment objeto que irá adicionar ao objeto de coleção existente WordprocessingCommentsPartComments . Fá-lo ao encontrar o valor de atributo mais alto Id dado a um Comment no objeto de Comments coleção, incrementando o valor por um e, em seguida, armazenando-o como o Id valor. Se não existir nenhuma WordprocessingCommentsPart parte, o código cria uma com o AddNewPart método do MainDocumentPart objeto e, em seguida, adiciona um Comments objeto de coleção ao mesmo.

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

Os Comment objetos e Comments representam elementos de comentários e comentários, respetivamente, no esquema Open XML Wordprocessing. Um Comment tem de ser adicionado a um Comments objeto para que o código instancia primeiro um Comments objeto (utilizando os argumentos authorde cadeia , initialse comments que foram transmitidos para o AddCommentOnFirstParagraph método).

O comentário é representado pelo seguinte exemplo de código WordprocessingML. .

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

Em seguida, o código acrescenta o Comment ao Comments objeto . Esta ação cria a estrutura de árvore do modelo de objeto de documento XML (DOM) necessária na memória, que consiste num comments elemento principal com comment elementos subordinados sob a mesma.

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

O seguinte exemplo de código wordprocessingML representa o conteúdo de uma parte de comentários num documento do WordprocessingML.

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

Com o Comment objeto instanciado, o código associa-o a Comment um intervalo no documento de processamento do Word. CommentRangeStart e CommentRangeEnd os objetos correspondem aos commentRangeStart elementos e commentRangeEnd no esquema Open XML Wordprocessing. Um CommentRangeStart objeto é dado como o argumento para o InsertBefore método do Paragraph objeto e um CommentRangeEnd objeto é transmitido para o InsertAfter método . Isto cria um intervalo de comentários que se estende de imediatamente antes do primeiro caráter do primeiro parágrafo no documento de processamento do Word para imediatamente após o último caráter do primeiro parágrafo.

Um CommentReference objeto representa um commentReference elemento no esquema Open XML Wordprocessing. Um commentReference liga um comentário específico na WordprocessingCommentsPart parte (o ficheiro Comments.xml no pacote de processamento do Word) a uma localização específica no corpo do documento (a MainDocumentPart parte contida no ficheiro Document.xml no pacote de processamento do Word). O id atributo do comentário, commentRangeStart, commentRangeEnd e commentReference é o mesmo para um determinado comentário, pelo que o atributo commentReference id tem de corresponder ao valor do atributo de comentário id ao qual está ligado. No exemplo, o código adiciona um commentReference elemento com a API e instancia um CommentReference objeto, especifica o valor e, em seguida, adiciona-o Id a um Run objeto.

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

Código de exemplo

O exemplo de código seguinte mostra como criar um comentário e associá-lo a um intervalo num documento de processamento de palavras. Para chamar o método AddCommentOnFirstParagraph pass no caminho do documento, o seu nome, as suas iniciais e o texto do comentário.

string fileName = args[0];
string author = args[1];
string initials = args[2];
string comment = args[3];

AddCommentOnFirstParagraph(fileName, author, initials, comment);

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

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

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

Confira também