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 GetPartsCountOfType
especifique 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 WordprocessingCommentsPart
Comments . 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 author
de cadeia , initials
e 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);
}
}