ワープロ ドキュメントにコメントを挿入する

適用対象: Excel 2010 | Office 2010 | PowerPoint 2010 | Word 2010

この記事の内容
既存のドキュメントを編集用に開く
サンプル コードの動作のしくみ
サンプル コード

ここでは、Open XML SDK 2.0 for Microsoft Office のクラスを使用して、プログラムによってワープロ ドキュメントの最初の段落にコメントを追加する方法を説明します。

このトピックのコードをコンパイルするには、次のアセンブリ ディレクティブが必要です。

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

既存のドキュメントを編集用に開く

既存のドキュメントを開くには、次の using ステートメントに示すように、WordprocessingDocument クラスをインスタンス化します。同じステートメントで、Open(String, Boolean) メソッドを使用し、Boolean パラメーターを true に設定してドキュメントの編集を有効にして、指定されている filepath にあるワープロ ファイルを開きます。

using (WordprocessingDocument document =
       WordprocessingDocument.Open(filepath, true)) 
{ 
   // Insert other code here. 
}
Using document As WordprocessingDocument = WordprocessingDocument.Open(filepath, True)
   ' Insert other code here. 
End Using

using ステートメントは、典型的な .Open, .Save, .Close シーケンスの代わりに使える推奨手段です。これを使用すると、対応する右かっこに達したとき、Dispose メソッド (Open XML SDK でリソースのクリーンアップに使われる内部メソッド) が自動的に呼び出されます。using ステートメントに続くブロックが、using ステートメントで作成または指定したオブジェクト (このケースでは document) のスコープとして設定されます。

サンプル コードの動作のしくみ

ドキュメントを開いた後、コメントを添付する最初の段落を探します。最初の段落を検索するには、種類が Paragraph であるドキュメント要素のすべての下位要素に対して、First 拡張メソッドを呼び出します。First メソッドは、System.Linq.Enumerable クラスのメンバーです。System.Linq.Enumerable クラスは、System.Collections.Generic.IEnumerable インターフェイスを実装するオブジェクトの拡張メソッドを提供します。

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

最初に、WordprocessingCommentsPart パーツが存在するかどうかを判別します。そのためには、MainDocumentPart の汎用メソッド GetPartsCountOfType を呼び出し、WordprocessingCommentsPart の種類を指定します。

WordprocessingCommentsPart パーツが存在する場合、既存の WordprocessingCommentsPartComments コレクション オブジェクトに追加する Comment オブジェクトの新しい Id 値を取得します。そのために、Comments コレクション オブジェクトの Comment に与えられた最も高い Id 属性値を見つけ、値を 1 つインクリメントして、Id 値として保存します。WordprocessingCommentsPart パーツが存在しない場合、MainDocumentPart オブジェクトの AddNewPart<T>() メソッドを使用して作成し、Comments コレクション オブジェクトを追加します。

if (document.MainDocumentPart.GetPartsCountOfType<WordprocessingCommentsPart>() > 0)
{
    comments = 
        document.MainDocumentPart.WordprocessingCommentsPart.Comments;
    if (comments.HasChildren)
    {
        id = comments.Descendants<Comment>().Select(e => e.Id.Value).Max();
    }
}
else
{
    WordprocessingCommentsPart commentPart = 
                document.MainDocumentPart.AddNewPart<WordprocessingCommentsPart>();
   commentPart.Comments = new Comments();
   comments = commentPart.Comments;
}
If document.MainDocumentPart.GetPartsCountOfType(Of WordprocessingCommentsPart)() > 0 Then
    comments = document.MainDocumentPart.WordprocessingCommentsPart.Comments
    If comments.HasChildren Then
        id = comments.Descendants(Of Comment)().Select(Function(e) e.Id.Value).Max()
    End If
Else
    Dim commentPart As WordprocessingCommentsPart = document.MainDocumentPart.AddNewPart(Of WordprocessingCommentsPart)()
    commentPart.Comments = New Comments()
    comments = commentPart.Comments
End If

Comment および Comments オブジェクトは、それぞれ、Open XML Wordprocessing スキーマにおいて単一コメント要素および複数コメント要素を表します。Comment を Comments オブジェクトに追加する必要があります。コードは、最初に Comments オブジェクトをインスタンス化します (AddCommentOnFirstParagraph メソッドに渡された文字列引数 author、initials、および comments を使用して)。

次の WordprocessingML コード例はコメントを表します。

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

コードは Comment を Comments オブジェクトに追加し、変更を保存します。これにより、comments 親要素とその下の comment 子要素で構成される必要な XML ドキュメント オブジェクト モデル (DOM) のツリー構造がメモリに作成されます。

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();
Dim p As New Paragraph(New Run(New Text(comment)))
Dim cmt As New Comment() With {.Id = id, .Author = author, .Initials = initials, .Date = Date.Now}
cmt.AppendChild(p)
comments.AppendChild(cmt)
comments.Save()

次の WordprocessingML コード例は、WordprocessingML ドキュメントのコメント パーツの内容を表します。

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

Comment オブジェクトがインスタンス化されている状態で、Comment を Wordprocessing ドキュメント内の範囲に関連付けます。CommentRangeStart および CommentRangeEnd オブジェクトは、Open XML Wordprocessing スキーマの commentRangeStart および commentRangeEnd 要素に対応します。CommentRangeStart オブジェクトが引数として Paragraph オブジェクトの InsertBefore<T>(T, OpenXmlElement) メソッドに渡され、CommentRangeEnd オブジェクトが InsertAfter<T>(T, OpenXmlElement) メソッドに渡されます。これによって、コメントの範囲が、Wordprocessing ドキュメントの最初の段落で、最初の文字の直前から最後の文字の直後まで作成されます。

CommentReference オブジェクトは、Open XML Wordprocessing スキーマの commentReference 要素を表します。commentReference は、WordprocessingCommentsPart パーツの特定のコメントを (ワープロ ドキュメントのパッケージの Comments.xml ファイル)、ドキュメント本体の特定の場所 (ワープロ ドキュメントのパッケージの Document.xml ファイルに含まれる MainDocumentPart パーツ) にリンクします。comment、commentRangeStart、commentRangeEnd、および commentReference の id 属性は、指定されたコメントの ID と同じです。したがって、commentReference id 属性は、リンク先の comment id 属性値と一致します。サンプルでは、API を使用して commentReference 要素を追加し、Id 値を指定して CommentReference オブジェクトをインスタンス化し、それを 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);
firstParagraph.InsertBefore(New CommentRangeStart() With {.Id = id}, firstParagraph.GetFirstChild(Of Run)())

        Dim cmtEnd = firstParagraph.InsertAfter(New CommentRangeEnd() With {.Id = id}, firstParagraph.Elements(Of Run)().Last())

        firstParagraph.InsertAfter(New Run(New CommentReference() With {.Id = id}), cmtEnd)

サンプル コード

次のコード例は、コメント作成し、ワープロ ドキュメント内の範囲に関連付ける方法を示します。AddCommentOnFirstParagraph メソッドを呼び出すには、ドキュメントのパス、ユーザーの名前、頭文字、およびコメント テキストを渡します。たとえば、次の AddCommentOnFirstParagraph メソッドの呼び出しでは、"This is my comment." というコメントが "Word8.docx" ファイルに書き込まれます。

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

以下は、C# および Visual Basic の完全なサンプル コードです。

// Insert a comment on the first paragraph.
public 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))
    {
        // Locate the first paragraph in the document.
        Paragraph firstParagraph = 
            document.MainDocumentPart.Document.Descendants<Paragraph>().First();
        Comments comments = null;
        string id = "0";

        // Verify that the document contains a 
        // WordProcessingCommentsPart part; if not, add a new one.
        if (document.MainDocumentPart.GetPartsCountOfType<WordprocessingCommentsPart>() > 0)
        {
            comments = 
                document.MainDocumentPart.WordprocessingCommentsPart.Comments;
            if (comments.HasChildren)
            {
                // Obtain an unused ID.
                id = comments.Descendants<Comment>().Select(e => e.Id.Value).Max();
            }
        }
        else
        {
            // No WordprocessingCommentsPart part exists, so add one to the package.
            WordprocessingCommentsPart commentPart = 
                document.MainDocumentPart.AddNewPart<WordprocessingCommentsPart>();
            commentPart.Comments = new Comments();
            comments = commentPart.Comments;
        }

        // 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);
        comments.AppendChild(cmt);
        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);
    }
}
' Insert a comment on the first paragraph.
Public Sub AddCommentOnFirstParagraph(ByVal fileName As String, ByVal author As String, ByVal initials As String, ByVal comment As String)
    ' Use the file name and path passed in as an 
    ' argument to open an existing Wordprocessing document. 
    Using document As WordprocessingDocument = WordprocessingDocument.Open(fileName, True)
        ' Locate the first paragraph in the document.
        Dim firstParagraph As Paragraph = document.MainDocumentPart.Document.Descendants(Of Paragraph)().First()
        Dim comments As Comments = Nothing
        Dim id As String = "0"

        ' Verify that the document contains a 
        ' WordProcessingCommentsPart part; if not, add a new one.
        If document.MainDocumentPart.GetPartsCountOfType(Of WordprocessingCommentsPart)() > 0 Then
            comments = document.MainDocumentPart.WordprocessingCommentsPart.Comments
            If comments.HasChildren Then
                ' Obtain an unused ID.
                id = comments.Descendants(Of Comment)().[Select](Function(e) e.Id.Value).Max()
            End If
        Else
            ' No WordprocessingCommentsPart part exists, so add one to the package.
            Dim commentPart As WordprocessingCommentsPart = document.MainDocumentPart.AddNewPart(Of WordprocessingCommentsPart)()
            commentPart.Comments = New Comments()
            comments = commentPart.Comments
        End If

        ' Compose a new Comment and add it to the Comments part.
        Dim p As New Paragraph(New Run(New Text(comment)))
        Dim cmt As New Comment() With {.Id = id, .Author = author, .Initials = initials, .Date = DateTime.Now}
        cmt.AppendChild(p)
        comments.AppendChild(cmt)
        comments.Save()

        ' Specify the text range for the Comment. 
        ' Insert the new CommentRangeStart before the first run of paragraph.
        firstParagraph.InsertBefore(New CommentRangeStart() With {.Id = id}, firstParagraph.GetFirstChild(Of Run)())

        ' Insert the new CommentRangeEnd after last run of paragraph.
        Dim cmtEnd = firstParagraph.InsertAfter(New CommentRangeEnd() With {.Id = id}, firstParagraph.Elements(Of Run)().Last())

        ' Compose a run with CommentReference and insert it.
        firstParagraph.InsertAfter(New Run(New CommentReference() With {.Id = id}), cmtEnd)
    End Using
End Sub

関連項目

参照

Class Library Reference

その他の技術情報

統合言語クエリ (LINQ: Language-Integrated Query)

拡張メソッド (C# プログラミング ガイド)

拡張メソッド (Visual Basic)