Open XML オブジェクト モデルを使用して Word 2007 ファイルを操作する (パート 1/3)

概要 :Microsoft SDK for Open XML Formats テクノロジ プレビュー」は、Open XML 形式のファイルを操作するためのライブラリです。この一連の記事では、Microsoft Office Word 2007 ファイルのアクセスと操作に使用できる Open XML オブジェクト モデルのコードについて説明します。(26 印刷ページ)

Frank Rice、Microsoft Corporation

2007 年 8 月

適用対象 : Microsoft Office Word 2007

目次

  • 背景

  • Office Open XML パッケージを作成する

  • ドキュメント内の変更履歴をすべて反映する

  • ドキュメント内のヘッダーを置換する

  • ドキュメントのコメントを削除する

  • ドキュメント内のヘッダーおよびフッターを削除する

  • まとめ

背景

2007 Microsoft Office system では、Open XML 形式と呼ばれる、XML に基づく新しいファイル形式が導入されています。Microsoft Office Word 2007、Microsoft Office Excel 2007、および Microsoft Office PowerPoint 2007 では、このファイル形式が既定のファイル形式として使用されます。Open XML 形式は、ZIP と XML という一般的なテクノロジに基づくオープン スタンダードであるため、使いやすいことが特徴です。Microsoft では、WinFX テクノロジの一部として、System.IO.Packaging 名前空間でこれらのファイルにアクセスするためのライブラリを「Microsoft SDK for Open XML Formats テクノロジ プレビュー」に用意しています。Open XML オブジェクト モデルは System.IO.Packaging アプリケーション プログラミング インターフェイス (API) を基盤として作成されており、Open XML ドキュメントを操作するための厳密に型指定されたパーツ クラスを備えています。この SDK を利用することで、Open XML パッケージの操作が容易になります。Open XML オブジェクト モデルは、開発者が Open XML パッケージに対して実行する一般的なタスクの多くをカプセル化しているため、複雑な操作を数行のコードで実行できます。

注意

Open XML 形式のファイルを操作するその他のサンプルおよび Open XML オブジェクト モデルに含まれている各メンバのリファレンスについては、「2007 Office system: Microsoft SDK for Open XML Formats」を参照してください。

Office Open XML パッケージ仕様では、XML ファイルのセットが定義されます。このファイル セットにより、1 つのパッケージに格納されるすべてのパーツのコンテンツが含まれ、各パーツのリレーションシップが定義されます。このパッケージには、Open XML 形式をサポートする 2007 Microsoft Office プログラム用のドキュメント ファイルを構成するパーツがまとめられます。この記事で説明する Open XML オブジェクト モデルを使用して、パッケージを作成し、そのパッケージを構成するファイルを操作することができます。この記事では、Word 2007 での Open XML パッケージのアクセスと操作に使用できるコードについて説明します。

Office Open XML パッケージを作成する

次のコードでは、Office Open XML パッケージを Word 2007 ドキュメントとして作成し、パッケージのメイン ドキュメント パーツにコンテンツを追加します。

Public Sub CreateNewWordDocument(ByVal document As String)
   Dim wordDoc As WordprocessingDocument = WordprocessingDocument.Create(document, WordprocessingDocumentType.Document)
   Using (wordDoc)
      ' Set the content of the document so that Word can open it.
      Dim mainPart As MainDocumentPart = wordDoc.AddMainDocumentPart
      SetMainDocumentContent(mainPart)
   End Using
End Sub

Public Sub SetMainDocumentContent(ByVal part As MainDocumentPart)
   Const docXml As String = "<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>" & _
   "<w:document xmlns:w=""http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html"">" & _
   "<w:body><w:p><w:r><w:t>Hello world!</w:t></w:r></w:p></w:body></w:document>"
   Dim stream1 As Stream = part.GetStream
   Dim utf8encoder1 As UTF8Encoding = New UTF8Encoding()
   Dim buf() As Byte = utf8encoder1.GetBytes(docXml)
   stream1.Write(buf, 0, buf.Length)
End Sub
// How to: Create a new package as a Word document.
public static void CreateNewWordDocument(string document)
{
   using (WordprocessingDocument wordDoc = WordprocessingDocument.Create(document, WordprocessingDocumentType.Document))
   {
      // Set the content of the document so that Word can open it.
      MainDocumentPart mainPart = wordDoc.AddMainDocumentPart();

      SetMainDocumentContent(mainPart);
   }
}

// Set content of MainDocumentPart.
public static void SetMainDocumentContent(MainDocumentPart part)
{
   const string docXml =
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> 
<w:document xmlns:w=""http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html"">
    <w:body><w:p><w:r><w:t>Hello world!</w:t></w:r></w:p></w:body>
</w:document>";

    using (Stream stream = part.GetStream())
    {
       byte[] buf = (new UTF8Encoding()).GetBytes(docXml);
       stream.Write(buf, 0, buf.Length);
    }
}

最初のプロシージャで、Word 2007 ドキュメントへのパスおよびドキュメント名を表すパラメータを渡します。次に、入力ドキュメントの名前に基づいてパッケージを表す WordprocessingDocument オブジェクトを作成します。残りのコードは、作成したオブジェクトをすべて適切に廃棄できるように using ステートメントにカプセル化されます。

次に、AddMainDocumentPart メソッドによりメイン ドキュメント パーツ (document.xml) を作成し、パッケージに追加します。メイン ドキュメント パーツはパッケージ内の /word フォルダに追加されます。次に、このメイン ドキュメント パーツで SetMainDocumentContent プロシージャが呼び出されます。このプロシージャは、Stream オブジェクトを使用し、Word 2007 ドキュメントの構造およびコンテンツを含む XML マークアップをパーツに追加します。次の構造でマークアップおよびテキストをパーツに追加します。

@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> 
<w:document xmlns:w=""http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html"">
   <w:body>
      <w:p>
         <w:r>
            <w:t>Hello world!</w:t>
         </w:r>
      </w:p>
   </w:body>
</w:document>

ドキュメント内の変更履歴をすべて反映する

次のコードでは、ドキュメント内の保留中の変更履歴がすべて反映されていることを Word 2007 に伝えるノードをメイン ドキュメント パーツから削除します。

Public Sub WDAcceptRevisions(ByVal docName As String, ByVal authorName As String)
   ' Given a document name and an author name (leave author name blank to accept revisions
   ' for all authors), accept revisions.
   Const wordmlNamespace As String = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html"
   Dim wdDoc As WordprocessingDocument = WordprocessingDocument.Open(docName, True)
   ' Manage namespaces to perform Xml XPath queries.
   Dim nt As NameTable = New NameTable
   Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt)
   nsManager.AddNamespace("w", wordmlNamespace)
   ' Get the document part from the package.
   Dim xdoc As XmlDocument = New XmlDocument(nt)
   ' Load the XML in the part into an XmlDocument instance.
   xdoc.Load(wdDoc.MainDocumentPart.GetStream)
   ' Handle formatting changes.
   Dim nodes As XmlNodeList = Nothing
   If String.IsNullOrEmpty(authorName) Then
      nodes = xdoc.SelectNodes("//w:pPrChange", nsManager)
   Else
      nodes = xdoc.SelectNodes(String.Format("//w:pPrChange[@w:author='{0}']", authorName), nsManager)
   End If
   For Each node As System.Xml.XmlNode In nodes
      node.ParentNode.RemoveChild(node)
   Next
   ' Handle deletions.
   If String.IsNullOrEmpty(authorName) Then
      nodes = xdoc.SelectNodes("//w:del", nsManager)
   Else
      nodes = xdoc.SelectNodes(String.Format("//w:del[@w:author='{0}']", authorName), nsManager)
   End If
   For Each node As System.Xml.XmlNode In nodes
      node.ParentNode.RemoveChild(node)
   Next
   ' Handle insertions.
   If String.IsNullOrEmpty(authorName) Then
      nodes = xdoc.SelectNodes("//w:ins", nsManager)
   Else
      nodes = xdoc.SelectNodes(String.Format("//w:ins[@w:author='{0}']", authorName), nsManager)
   End If
   For Each node As System.Xml.XmlNode In nodes
      ' You found one or more new content.
      ' Promote them to the same level as node, and then
      ' delete the node.
      Dim childNodes As XmlNodeList
      childNodes = node.SelectNodes(".//w:r", nsManager)
      For Each childNode As System.Xml.XmlNode In childNodes
         If (childNode Is node.FirstChild) Then
            node.ParentNode.InsertAfter(childNode, node)
         Else
            node.ParentNode.InsertAfter(childNode, node.NextSibling)
         End If
      Next
         node.ParentNode.RemoveChild(node)
         ' Remove the modification id from the node 
         ' so Word can merge it on the next save.
         node.Attributes.RemoveNamedItem("w:rsidR")
         node.Attributes.RemoveNamedItem("w:rsidRPr")
   Next
   ' Save the document XML back to its part.
   xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create))
End Sub
public static void WDAcceptRevisions(string docName, string authorName)
{
   // Given a document name and an author name (leave author name blank to accept revisions
   // for all authors), accept revisions.

   const string wordmlNamespace = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html";

   using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(docName, true))
   {
       // Manage namespaces to perform Xml XPath queries.
       NameTable nt = new NameTable();
       XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
       nsManager.AddNamespace("w", wordmlNamespace);

       // Get the document part from the package.
       XmlDocument xdoc = new XmlDocument(nt);
       // Load the XML in the part into an XmlDocument instance.
       xdoc.Load(wdDoc.MainDocumentPart.GetStream());

       // Handle formatting changes.
       XmlNodeList nodes = null;
       if (string.IsNullOrEmpty(authorName))
       {
           nodes = xdoc.SelectNodes("//w:pPrChange", nsManager);
       }
       else
       {
          nodes = xdoc.SelectNodes(string.Format("//w:pPrChange[@w:author='{0}']", authorName), nsManager);
       }
       foreach (System.Xml.XmlNode node in nodes)
       {
          node.ParentNode.RemoveChild(node);
       }

       // Handle deletions.
       if (string.IsNullOrEmpty(authorName))
       {
          nodes = xdoc.SelectNodes("//w:del", nsManager);
       }
       else
       {
          nodes = xdoc.SelectNodes(string.Format("//w:del[@w:author='{0}']", authorName), nsManager);
       }

       foreach (System.Xml.XmlNode node in nodes)
       {
           node.ParentNode.RemoveChild(node);
       }


       // Handle insertions.
       if (string.IsNullOrEmpty(authorName))
       {
          nodes = xdoc.SelectNodes("//w:ins", nsManager);
       }
       else
       {
          nodes = xdoc.SelectNodes(string.Format("//w:ins[@w:author='{0}']", authorName), nsManager);
       }

       foreach (System.Xml.XmlNode node in nodes)
       {
          // You found one or more new content.
          // Promote them to the same level as node, and then
          // delete the node.
          XmlNodeList childNodes;
          childNodes = node.SelectNodes(".//w:r", nsManager);
          foreach (System.Xml.XmlNode childNode in childNodes)
          {
             if (childNode == node.FirstChild)
             {
                 node.ParentNode.InsertAfter(childNode, node);
             }
             else
             {
                 node.ParentNode.InsertAfter(childNode, node.NextSibling);
              }
           }
           node.ParentNode.RemoveChild(node);

           // Remove the modification id from the node 
           // so Word can merge it on the next save.
           node.Attributes.RemoveNamedItem("w:rsidR");
           node.Attributes.RemoveNamedItem("w:rsidRPr");
       }

       // Save the document XML back to its part.
       xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create));
   }
}

このプロシージャでは、最初にソース Word 2007 ドキュメントへのパスとドキュメント名 (および、必要に応じてドキュメント作成者の名前) を表すパラメータを渡します。

注意

作成者名を指定しない場合でも空の文字列を渡す必要があります。

WordprocessingDocument オブジェクトの Open メソッドを使用して、ドキュメントを開きます。さらに、XmlNamespaceManager オブジェクトを使用して名前空間マネージャを設定します。修飾子 (w) を使用して既定の WordprocessingML 名前空間への参照を設定します。メイン ドキュメント パーツ (/word/document.xml) のコンテンツが、メモリ常駐の XML ドキュメントに読み込まれます。次に、XPath 式を使用して、特定の作成者 (作成者名を指定した場合) によって割り当てられた変更履歴について [w:pPrChange] ノードをテストします。作成者名がプロシージャに渡されていない場合、すべての作成者によるすべての変更履歴が対象となります。ただし、次のステートメントでは、すべての [w:pPrChange] ノード (存在する場合) が選択されます。

nodes = xdoc.SelectNodes("//w:pPrChange", nsManager)
nodes = xdoc.SelectNodes("//w:pPrChange", nsManager);

これらのノードは、ドキュメントに対する保留中の書式変更を示します。削除の場合はノード名 w:del を、挿入の場合は w:ins を指定して、同じようにすべてのノードを選択できます。次のステートメントでは、検出されたノードの子ノードが削除されます。

node.ParentNode.RemoveChild(node)
node.ParentNode.RemoveChild(node);

このしくみを理解するために、次の例について考えてみます。ドキュメントの校閲中に、1 行のテキストを選択して Title スタイルを適用したとします。この操作により、次の WordprocessingML マークアップがメイン ドキュメント パーツに生成されます。

<w:pPr>
   <w:pStyle w:val="Title" /> 
      <w:pPrChange w:id="0" w:author="Nancy Davolio" w:date="2007-07-03T08:22:00Z">
         <w:pPr /> 
      </w:pPrChange>
</w:pPr>
<w:r w:rsidRPr="00655EFA">
  <w:t>Gettysburg Address</w:t> 
</w:r>

w:pStyle 要素は、これがスタイル変更であることを示します。ここでは、このスタイル変更により、選択されたテキストに Title スタイルが設定されます。w:pPrChange 要素は、変更履歴の作成者と日付を示します。また、変更が保留中であることを Word 2007 に伝える役割も果たします。w:r 要素および w:t 要素により、実行とテキストがそれぞれ指定されます。これには選択中のテキスト (この場合は Gettysburg Address) が含まれます。Word 2007 でドキュメントを校閲する場合、テキストを選択し、[校閲] タブの [承諾] をクリックし、[承諾して次へ進む] をクリックします。Word 2007 は、変更を反映し、w:pPrChange 要素を削除します。コードを使用してこの動作をエミュレートできます。w:pPrChange 要素を削除するコードを使用すると、変更履歴の反映と同じ結果を得ることができます。この処理は、次のステートメントで実行されます。

node.ParentNode.RemoveChild(node)
node.ParentNode.RemoveChild(node);

ここで、現在のノードは w:pPrChange 要素です。現在のノード ( w:pPrChange 要素) を削除するには、現在のノードの親 (w:pStyle 要素) を指定し、RemoveChild メソッドを呼び出します。この方法で現在のノードを削除することは、変更を反映することと同じです。w:del 要素による削除の場合も、同様のプロセスが実行されます。

挿入では w:ins 要素が 1 つまたは複数の挿入のコンテナである場合があるため、他の書式変更よりも複雑です。たとえば、次の WordprocessingML マークアップで示すように、1 つの操作でテキストとスペースを挿入する場合があります。

<w:ins w:id="12" w:author="Nancy Davolio" w:date="2007-07-03T08:23:00Z">
   <w:r w:rsidR="00655EFA">
      <w:t>word</w:t> 
   </w:r>
   <w:proofErr w:type="spellEnd" /> 
   <w:r w:rsidR="00655EFA">
      <w:t xml:space="preserve"></w:t> 
   </w:r>
</w:ins>

このセグメントでは、ドキュメントに word という単語が挿入され、その後に空白スペースが挿入されます。これらの w:t テキスト要素は両方とも w:r run 要素に含まれます。この要素は w:ins 挿入要素に含まれます。プログラミング コード プロシージャで、これらのノード ([w:ins] ノードの子ノード) は [w:ins] ノードと同じレベルに昇格されます。続いて [w:ins] ノードが削除されることで、変更履歴の反映と同じ結果が得られます。

nodes = xdoc.SelectNodes("//w:ins", nsManager)
...
For Each childNode As System.Xml.XmlNode In childNodes
   If (childNode Is node.FirstChild) Then
      node.ParentNode.InsertAfter(childNode, node)
   Else
      node.ParentNode.InsertAfter(childNode, node.NextSibling)
   End If
Next
node.ParentNode.RemoveChild(node)
nodes = xdoc.SelectNodes("//w:ins", nsManager);
...
childNodes = node.SelectNodes(".//w:r", nsManager);
foreach (System.Xml.XmlNode childNode in childNodes)
{
   if (childNode == node.FirstChild)
   {
       node.ParentNode.InsertAfter(childNode, node);
   }
   else
   {
       node.ParentNode.InsertAfter(childNode, node.NextSibling);
   }
}
node.ParentNode.RemoveChild(node);

この操作が困難になるのは、w:t テキスト要素が処理される順序が適切でない場合です。前述の例で、特定の位置に word という単語を挿入し、その後ろに空白スペースを挿入するとします。まず、word の w:t 要素が処理され、親ノード (w:r) の後に挿入されます。次に、スペースの w:t 要素が処理され、同じように親ノードの後に挿入されます。その結果、w:r 親要素の後にスペースが表示され、その後にテキストの word が表示されます。これは期待した結果とは逆です。この問題を回避するには、テキスト要素の順序を検出する方法が必要です。このコードでは、最初に w:t 要素を親ノードの後に配置し、次に後続の要素を最初の子ノードの後に挿入します。

ノードの順序を適切に配置した後で、該当するノードを削除し、更新された XML をドキュメント パーツに保存します。更新されたドキュメントを開いたときに、XML ステートメントが不足しているため、Word 2007 に変更履歴が反映されたことが通知されます。

ドキュメント内のヘッダーを置換する

次のコードでは、ドキュメント内の既存のヘッダー パーツを削除し、WordprocessingML マークアップで置換して、ドキュメントのヘッダーを変更します。

Public Sub WDAddHeader(ByVal docName As String, ByVal headerContent As Stream)
   ' Given a document name, and a stream containing valid header content,
   ' add the stream content as a header in the document and remove the original headers
   Const wordmlNamespace As String = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html"
   Const relationshipNamespace As String = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html"
   Dim wdDoc As WordprocessingDocument = WordprocessingDocument.Open(docName, True)

   Using (wdDoc)
      ' Delete existing header part
      wdDoc.MainDocumentPart.DeleteParts(wdDoc.MainDocumentPart.HeaderParts)

      ' Create a new header part.
      Dim headerPart As HeaderPart = wdDoc.MainDocumentPart.AddNewPart(Of HeaderPart)()
      Dim rId As String = wdDoc.MainDocumentPart.GetIdOfPart(headerPart)
      Dim headerDoc As XmlDocument = New XmlDocument
      headerContent.Position = 0
      headerDoc.Load(headerContent)

      ' Write the header out to its part.
      headerDoc.Save(headerPart.GetStream)

      ' Manage namespaces to perform Xml XPath queries.
      Dim nt As NameTable = New NameTable
      Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt)
      nsManager.AddNamespace("w", wordmlNamespace)

      ' Get the document part from the package.
      ' Load the XML in the part into an XmlDocument instance.
      Dim xdoc As XmlDocument = New XmlDocument(nt)
      xdoc.Load(wdDoc.MainDocumentPart.GetStream)

      ' Find the node containing the document layout.
      Dim targetNodes As XmlNodeList = xdoc.SelectNodes("//w:sectPr", nsManager)
      For Each targetNode As XmlNode In targetNodes
         ' Delete any existing references to headers.
         Dim headerNodes As XmlNodeList = targetNode.SelectNodes("./w:headerReference", nsManager)
         For Each headerNode As System.Xml.XmlNode In headerNodes
            targetNode.RemoveChild(headerNode)
         Next
         ' Create the new header reference node.
         Dim node As XmlElement = xdoc.CreateElement("w:headerReference", wordmlNamespace)
         Dim attr As XmlAttribute = node.Attributes.Append(xdoc.CreateAttribute("r:id", relationshipNamespace))
         attr.Value = rId
         node.Attributes.Append(attr)
         targetNode.InsertBefore(node, targetNode.FirstChild)
      Next

      ' Save the document XML back to its part.
      xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create))
   End Using
End Sub
public static void WDAddHeader(string docName, Stream headerContent)
{
   // Given a document name, and a stream containing valid header content,
   // add the stream content as a header in the document and remove the original headers

   const string wordmlNamespace = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html";
   const string relationshipNamespace = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html";

   using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(docName, true))
   {
      // Delete existing header part.
      wdDoc.MainDocumentPart.DeleteParts(wdDoc.MainDocumentPart.HeaderParts);

      // Create a new header part.
      HeaderPart headerPart = wdDoc.MainDocumentPart.AddNewPart<HeaderPart>();
      string rId = wdDoc.MainDocumentPart.GetIdOfPart(headerPart);                
      XmlDocument headerDoc = new XmlDocument();
      headerContent.Position = 0;
      headerDoc.Load(headerContent);

      // Write the header out to its part.
      headerDoc.Save(headerPart.GetStream());

      // Manage namespaces to perform Xml XPath queries.
      NameTable nt = new NameTable();
      XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
      nsManager.AddNamespace("w", wordmlNamespace);

      // Get the document part from the package.
      // Load the XML in the part into an XmlDocument instance.
      XmlDocument xdoc = new XmlDocument(nt);
      xdoc.Load(wdDoc.MainDocumentPart.GetStream());

      // Find the node containing the document layout.
      XmlNodeList targetNodes = xdoc.SelectNodes("//w:sectPr", nsManager);
      foreach (XmlNode targetNode in targetNodes)
      {
         // Delete any existing references to headers.
         XmlNodeList headerNodes = targetNode.SelectNodes("./w:headerReference", nsManager);
         foreach (System.Xml.XmlNode headerNode in headerNodes)
         {
            targetNode.RemoveChild(headerNode);
         }

         // Create the new header reference node.
         XmlElement node = xdoc.CreateElement("w:headerReference", wordmlNamespace);
         XmlAttribute attr = node.Attributes.Append(xdoc.CreateAttribute("r:id", relationshipNamespace));
         attr.Value = rId;
         node.Attributes.Append(attr);
         targetNode.InsertBefore(node, targetNode.FirstChild);
      }

      // Save the document XML back to its part.
      xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create));
   }
}

最初に、WDAddHeader メソッドが呼び出され、Word 2007 ドキュメントへの参照および Stream オブジェクトが渡されます。このオブジェクトには、置換ヘッダー マークアップおよびデータが格納されています。次に、Open XML ファイル形式パッケージを表す WordprocessingDocument オブジェクト、および WordprocessingML マークアップの名前空間マネージャを設定します。次のコードで、ドキュメント内の既存のヘッダー パーツを削除し、空白のヘッダー パーツを作成します。

wdDoc.MainDocumentPart.DeleteParts(wdDoc.MainDocumentPart.HeaderParts)

' Create a new header part.
Dim headerPart As HeaderPart = wdDoc.MainDocumentPart.AddNewPart(Of HeaderPart)()
Dim headerDoc As XmlDocument = New XmlDocument
headerContent.Position = 0
headerDoc.Load(headerContent)

' Write the header out to its part.
headerDoc.Save(headerPart.GetStream)
wdDoc.MainDocumentPart.DeleteParts(wdDoc.MainDocumentPart.HeaderParts);

// Create a new header part.
HeaderPart headerPart = wdDoc.MainDocumentPart.AddNewPart<HeaderPart>();

XmlDocument headerDoc = new XmlDocument();
headerContent.Position = 0;
headerDoc.Load(headerContent);

// Write the header out to its part.
headerDoc.Save(headerPart.GetStream());

次に、メモリ常駐 XML ドキュメントを一時ホルダとして作成し、そのドキュメントに置換ヘッダーを表すマークアップおよびデータをロードします。その後のコードで、メイン ドキュメント パーツで先ほど削除したヘッダー パーツへの参照を検索します。この検索では、XPath クエリを使用して該当する名前空間を検索し、それを削除し、新しいヘッダー パーツへの参照を挿入します。最後に、更新された WordprocessingML マークアップが元のメイン ドキュメント パーツに保存されます。

ドキュメントのコメントを削除する

次のコードでは、Word 2007 ドキュメントのコメント パーツおよびそのパーツへの参照をすべて削除します。

Public Sub WDDeleteComments(ByVal docName As String)
   ' Given a document name, remove all comments.
   Const wordmlNamespace As String = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html"
   Dim wdDoc As WordprocessingDocument = WordprocessingDocument.Open(docName, true)
   If (Not (wdDoc.MainDocumentPart.CommentsPart) Is Nothing) Then
      wdDoc.MainDocumentPart.DeletePart(wdDoc.MainDocumentPart.CommentsPart)

      ' Manage namespaces to perform Xml XPath queries.
      Dim nt As NameTable = New NameTable
      Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt)
      nsManager.AddNamespace("w", wordmlNamespace)

      ' Get the document part from the package.
      ' Load the XML in the part into an XmlDocument instance:
      Dim xdoc As XmlDocument = New XmlDocument(nt)
      xdoc.Load(wdDoc.MainDocumentPart.GetStream)

      ' Retrieve a list of nodes representing the comment start elements, and delete them all.
      Dim nodes As XmlNodeList = xdoc.SelectNodes("//w:commentRangeStart", nsManager)
      For Each node As System.Xml.XmlNode In nodes
         node.ParentNode.RemoveChild(node)
      Next

      ' Retrieve a list of nodes representing the comment end elements, and delete them all.
      nodes = xdoc.SelectNodes("//w:commentRangeEnd", nsManager)
      For Each node As System.Xml.XmlNode In nodes
         node.ParentNode.RemoveChild(node)
      Next

      ' Retrieve a list of nodes representing the comment reference elements, and delete them all.
      nodes = xdoc.SelectNodes("//w:r/w:commentReference", nsManager)
      For Each node As System.Xml.XmlNode In nodes
                node.ParentNode.RemoveChild(node)
      Next

      ' Save the document XML back to its part.
      xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create))
   End If
End Sub
public static void WDDeleteComments(string docName)
{
   // Given a document name, remove all comments.

   const string wordmlNamespace = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html";

   using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(docName, true))
   {
      if (wdDoc.MainDocumentPart.CommentsPart != null)
      {
         wdDoc.MainDocumentPart.DeletePart(wdDoc.MainDocumentPart.CommentsPart);
         // Manage namespaces to perform Xml XPath queries.
         NameTable nt = new NameTable();
         XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
         nsManager.AddNamespace("w", wordmlNamespace);

         // Get the document part from the package.
         // Load the XML in the part into an XmlDocument instance:
         XmlDocument xdoc = new XmlDocument(nt);
         xdoc.Load(wdDoc.MainDocumentPart.GetStream());

         // Retrieve a list of nodes representing the comment start elements, and delete them all.
         XmlNodeList nodes = xdoc.SelectNodes("//w:commentRangeStart", nsManager);
         foreach (System.Xml.XmlNode node in nodes)
         {
            node.ParentNode.RemoveChild(node);
         }

         // Retrieve a list of nodes representing the comment end elements, and delete them all.
         nodes = xdoc.SelectNodes("//w:commentRangeEnd", nsManager);
         foreach (System.Xml.XmlNode node in nodes)
         {
            node.ParentNode.RemoveChild(node);
         }

         // Retrieve a list of nodes representing the comment reference elements, and delete them all.
         nodes = xdoc.SelectNodes("//w:r/w:commentReference", nsManager);
         foreach (System.Xml.XmlNode node in nodes)
         {
            node.ParentNode.RemoveChild(node);
         }

         // Save the document XML back to its part.
         xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create));
      }
   }
}

最初に、WDDeleteComments メソッドが呼び出され、Word 2007 ドキュメントへの参照が渡されます。次に、Open XML ファイル形式パッケージを表す WordprocessingDocument オブジェクトが入力ドキュメントに基づいて作成されます。次に、パッケージにコメント パーツが存在するかどうかが確認され、存在する場合は削除されます。XPath クエリを設定するために名前空間マネージャが作成されます。このクエリは、//w:commentRangeStart と //w:commentRangeEnd XPath 式を使用し、メイン ドキュメント パーツで開始コメント ノードおよび終了コメント ノードをそれぞれ検索します。リストが完了すると、各ノードが削除されます。

Dim nodes As XmlNodeList = xdoc.SelectNodes("//w:commentRangeStart", nsManager)
For Each node As System.Xml.XmlNode In nodes
   node.ParentNode.RemoveChild(node)
Next

' Retrieve a list of nodes representing the comment end elements, and delete them all.
nodes = xdoc.SelectNodes("//w:commentRangeEnd", nsManager)
For Each node As System.Xml.XmlNode In nodes
   node.ParentNode.RemoveChild(node)
Next
XmlNodeList nodes = xdoc.SelectNodes("//w:commentRangeStart", nsManager);
foreach (System.Xml.XmlNode node in nodes)
{
   node.ParentNode.RemoveChild(node);
}

// Retrieve a list of nodes representing the comment end elements, and delete them all.
nodes = xdoc.SelectNodes("//w:commentRangeEnd", nsManager);
foreach (System.Xml.XmlNode node in nodes)
{
   node.ParentNode.RemoveChild(node);
}

//w:r/w:commentReference XPath 式を使用してコメントを参照するノードを削除する場合も、同じプロセスが使用されます。最後に、更新された WordprocessingML マークアップが元のメイン ドキュメント パーツに保存されます。

ドキュメント内のヘッダーおよびフッターを削除する

次のコードでは、Word 2007 ドキュメントのヘッダーとフッターを削除します。

Public Sub WDRemoveHeadersFooters(ByVal docName As String)
   ' Given a document name, remove all headers and footers.
   Const wordmlNamespace As String = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html"
   Dim wdDoc As WordprocessingDocument = WordprocessingDocument.Open(docName, true)
   Using (wdDoc)
      If ((wdDoc.MainDocumentPart.GetPartsCountOfType(Of HeaderPart)() > 0) OR (wdDoc.MainDocumentPart.GetPartsCountOfType(Of FooterPart)() > 0))
         wdDoc.MainDocumentPart.DeleteParts(wdDoc.MainDocumentPart.HeaderParts)
         wdDoc.MainDocumentPart.DeleteParts(wdDoc.MainDocumentPart.FooterParts)

         ' Manage namespaces to perform XPath queries.
         Dim nt As NameTable = New NameTable
         Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt)
         nsManager.AddNamespace("w", wordmlNamespace)

         ' Get the document part from the package.
         ' Load the XML in the part into an XmlDocument instance.
         Dim xdoc As XmlDocument = New XmlDocument(nt)
         xdoc.Load(wdDoc.MainDocumentPart.GetStream)

         ' Find the node containing the document layout.
         Dim layoutNodes As XmlNodeList = xdoc.SelectNodes("//w:sectPr", nsManager)
         For Each layoutNode As System.Xml.XmlNode In layoutNodes
            ' Delete any existing references to headers.
            Dim headerNodes As XmlNodeList = layoutNode.SelectNodes("./w:headerReference", nsManager)
            For Each headerNode As System.Xml.XmlNode In headerNodes
               layoutNode.RemoveChild(headerNode)
            Next

            ' Delete any existing references to footers.
            Dim footerNodes As XmlNodeList = layoutNode.SelectNodes("./w:footerReference", nsManager)
            For Each footerNode As System.Xml.XmlNode In footerNodes
               layoutNode.RemoveChild(footerNode)
            Next
         Next

         ' Save the document XML back to its part.
         xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create))
      End If
   End Using
End Sub
public static void WDRemoveHeadersFooters(string docName)
{
   // Given a document name, remove all headers and footers.

   const string wordmlNamespace = "http://schemas.liquid-technologies.com/OfficeOpenXML/2006/default.html";

   using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(docName, true))
   {
      if (wdDoc.MainDocumentPart.GetPartsCountOfType<HeaderPart>() > 0 ||
        wdDoc.MainDocumentPart.GetPartsCountOfType<FooterPart>() > 0)
      {
         wdDoc.MainDocumentPart.DeleteParts(wdDoc.MainDocumentPart.HeaderParts);
         wdDoc.MainDocumentPart.DeleteParts(wdDoc.MainDocumentPart.FooterParts);

         // Manage namespaces to perform XPath queries.
         NameTable nt = new NameTable();
         XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
         nsManager.AddNamespace("w", wordmlNamespace);

         // Get the document part from the package.
         // Load the XML in the part into an XmlDocument instance.
         XmlDocument xdoc = new XmlDocument(nt);
         xdoc.Load(wdDoc.MainDocumentPart.GetStream());

         // Find the node containing the document layout.
         XmlNodeList layoutNodes = xdoc.SelectNodes("//w:sectPr", nsManager);
         foreach (System.Xml.XmlNode layoutNode in layoutNodes)
         {
            // Delete any existing references to headers.
            XmlNodeList headerNodes = layoutNode.SelectNodes("./w:headerReference", nsManager);
            foreach (System.Xml.XmlNode headerNode in headerNodes)
            {
               layoutNode.RemoveChild(headerNode);
            }

            // Delete any existing references to footers.
            XmlNodeList footerNodes = layoutNode.SelectNodes("./w:footerReference", nsManager);
            foreach (System.Xml.XmlNode footerNode in footerNodes)
            {
               layoutNode.RemoveChild(footerNode);
            }
         }

         // Save the document XML back to its part.
         xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create));
      }
   }
}

最初に、WDRemoveHeadersFooters メソッドが呼び出され、Word 2007 ドキュメントへの参照が渡されます。次に、Open XML ファイル形式パッケージを表す WordprocessingDocument オブジェクトが入力ドキュメントに基づいて作成されます。次に、パッケージにヘッダー パーツおよびフッター パーツが存在するかどうかが確認され、存在する場合は削除されます。XPath クエリを設定するために名前空間マネージャが作成されます。

次に、メモリ常駐 XML ドキュメントを一時ホルダとして作成し、そのドキュメントにメイン ドキュメント パーツからマークアップおよびデータをロードします。この後のコードで、先ほど削除したヘッダーおよびフッター パーツを参照するノードを検索し、それらを削除します。

Dim layoutNodes As XmlNodeList = xdoc.SelectNodes("//w:sectPr", nsManager)
For Each layoutNode As System.Xml.XmlNode In layoutNodes
   ' Delete any existing references to headers.
   Dim headerNodes As XmlNodeList = layoutNode.SelectNodes("./w:headerReference", nsManager)
   For Each headerNode As System.Xml.XmlNode In headerNodes
      layoutNode.RemoveChild(headerNode)
   Next

   ' Delete any existing references to footers.
   Dim footerNodes As XmlNodeList = layoutNode.SelectNodes("./w:footerReference", nsManager)
   For Each footerNode As System.Xml.XmlNode In footerNodes
      layoutNode.RemoveChild(footerNode)
   Next
Next
XmlNodeList layoutNodes = xdoc.SelectNodes("//w:sectPr", nsManager);
foreach (System.Xml.XmlNode layoutNode in layoutNodes)
{
   // Delete any existing references to headers.
   XmlNodeList headerNodes = layoutNode.SelectNodes("./w:headerReference", nsManager);
   foreach (System.Xml.XmlNode headerNode in headerNodes)
   {
      layoutNode.RemoveChild(headerNode);
   }

   // Delete any existing references to footers.
   XmlNodeList footerNodes = layoutNode.SelectNodes("./w:footerReference", nsManager);
   foreach (System.Xml.XmlNode footerNode in footerNodes)
   {
      layoutNode.RemoveChild(footerNode);
   }
}

最後に、更新された WordprocessingML マークアップが元のメイン ドキュメント パーツに保存されます。

まとめ

この記事で説明したように、「Microsoft SDK for Open XML Formats テクノロジ プレビュー」を参照することで、Word 2007 ファイルの操作が非常に簡単になります。このシリーズのパート 2 の記事では、Open XML Formats SDK で実行できる他の一般的なタスクについて説明します。

追加情報

詳細については、以下のリソースを参照してください。

準備中 :