在字处理文档中插入注释
本主题演示如何使用 Open XML SDK for Office 中的类以编程方式向字处理文档中的第一段添加注释。
打开现有文档以进行编辑
若要打开现有文档,请实例化 类, WordprocessingDocument 如以下 using
语句所示。 在同一语句中,使用 Open(String, Boolean) 方法打开指定 filepath 处的字处理文件,并将布尔参数设置为 true
以启用文档中的编辑。
using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true))
在 v3.0.0+ 中, Close() 已删除 方法,转而依赖于 using 语句。
它确保在 Dispose() 到达右大括号时自动调用 方法。 using 语句后面的块为 using 语句中创建或指定的对象设定范围。
WordprocessingDocument由于 Open XML SDK 中的 类会自动保存并关闭对象作为其IDisposable实现的一using
部分,并且由于Dispose()在退出块时会自动调用,因此无需显式调用 Save() 或 Dispose() ,只要使用 语句。
示例代码的工作方式
打开文档后,可以找到要附加文档的第一个段落。 代码通过对类型 Paragraph为 的文档元素的所有后代元素调用First扩展方法来查找第一个段落。 方法 First
是 类的成员 Enumerable 。 类 System.Linq.Enumerable
为实现 IEnumerable<T> 接口的对象提供扩展方法。
Paragraph firstParagraph = document.MainDocumentPart.Document.Descendants<Paragraph>().First();
wordprocessingCommentsPart.Comments ??= new Comments();
string id = "0";
代码首先确定部件 WordprocessingCommentsPart 是否存在。 为此,请调用 MainDocumentPart 泛型方法 GetPartsCountOfType
,并指定一种 WordprocessingCommentsPart
。
如果部件WordprocessingCommentsPart
存在,则代码将为Comment对象获取一个新Id
值,该对象将添加到现有WordprocessingCommentsPart
Comments集合对象。 为此,Id
它会在集合对象中Comments
查找给定的最高Comment
属性值,将值递增 1,然后将其存储为Id
值。如果不存在部件WordprocessingCommentsPart
,则代码使用 AddNewPart 对象的 方法MainDocumentPart创建一个Comments
,然后将集合对象添加到其中。
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();
}
}
Comment
和 Comments
对象分别表示 Open XML Wordprocessing 架构中的注释和注释元素。
Comment
必须将 添加到 对象中,Comments
以便代码首先使用传递给 AddCommentOnFirstParagraph
方法的字符串参数 author
、 initials
和 comments
实例化Comments
对象 () 。
注释由以下 WordprocessingML 代码示例表示。 .
<w:comment w:id="1" w:initials="User">
...
</w:comment>
然后,代码会将 Comment
追加到 对象。Comments
这会在内存中创建所需的 XML 文档对象模型 (DOM) 树结构,该结构由父元素和comment
子元素组成comments
。
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);
以下 WordprocessingML 代码示例表示 WordprocessingML 文档中的注释部件的内容。
<w:comments>
<w:comment … >
…
</w:comment>
</w:comments>
在 Comment
实例化 对象后,代码会将 Comment
与 Wordprocessing 文档中的区域相关联。
CommentRangeStart 和 CommentRangeEnd 对象对应于 commentRangeStart
Open XML Wordprocessing 架构中的 和 commentRangeEnd
元素。
对象CommentRangeStart
作为 对象的 方法Paragraph的参数InsertBefore提供,CommentRangeEnd
对象传递给 InsertAfter 方法。
这将创建一个注释区域,从 Wordprocessing 文档中第一个段落的第一个字符的紧前面延伸到第一个段落的最后一个字符的紧后面。
对象 CommentReference 表示 commentReference
Open XML Wordprocessing 架构中的元素。 commentReference 将 Wordprocessing 包) (Comments.xml 部件中的特定注释 WordprocessingCommentsPart
链接到文档正文中的特定位置, (MainDocumentPart
wordprocessing 包) Document.xml 文件中包含的部件。 给定注释的 comment、commentRangeStart、commentRangeEnd 和 commentReference 的 id
属性是相同的,这样 commentReference id
属性必须匹配其链接到的 comment id
属性值。 在示例中,代码使用 API 添加 commentReference
元素,并实例化对象 CommentReference
,指定 Id
值,然后将其添加到 Run 对象。
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);
示例代码
下面的代码示例演示如何创建注释并将其与字处理文档中的某个区域相关联。 若要调用 方法 AddCommentOnFirstParagraph
,请传入文档的路径、姓名、姓名缩写和注释文本。
string fileName = args[0];
string author = args[1];
string initials = args[2];
string comment = args[3];
AddCommentOnFirstParagraph(fileName, author, initials, comment);
以下是使用 C# 和 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);
}
}