Word の Content Control を使った Office Add-ins のドキュメント テンプレート

Office Add-ins (旧 App for Office) について記事を書いたので紹介したい。

@IT : Officeストアで世界に飛び出そう! 最新Office 2013アプリ開発入門

前編は、まず、Office Add-ins がどのようなものか基本を理解し、後編で、「じゃあ、どのような設計方針で作っていくか」、「どこまで出来て、どこからできないか」 など全体像を解説して理解を深めてもらう予定だ。(既に原稿はあるが、結構きれいにまとめたつもりなので期待しててほしい。)

後編で解説するが、Word を使用した Office Add-in では Custom XML Part と連携したアプリ開発も可能で、Word のドキュメント テンプレートと組み合わせた Office Add-in (Task-pane Add-in) も作成可能だ。ただ、この辺りを万人にわかるようにちゃんと説明すると、「そもそも Custom XML Part って何 ?」 から始まり、さらに動くソース コードまで載せると、それだけでも長い記事になってしまうので、この辺りは「できること」、「できないこと」を明示する程度の解説を予定している。

そこで、この投稿では、ちょっとその辺りの開発手法について補足しておこう。

Content Control と Custom XML Part

まずは、背景から解説する。

Word のコンテンツ コントロール (Content Control) とは、 Word に挿入できるテキスト ボックスやチェック ボックスなどの入力欄のことで、 Word (Word 2007 以上) のリボンの開発タブ (Developer Tab) を表示することで挿入できる。下図のようなフォームを作成する際に使えるコントロールだ。

ContentsControl

さて、この Content Control の嬉しい点は、 Word (Word 2007 以上) の Office OpenXML (OOXML) とのバインドが可能な点だ。

例えば、Office Open XML (OOXML) のフォーマットになってから、 Word 文書には独自の XML ファイル (外部システムで作成した XML ファイルなど) が挿入できるようになっていて、 これをカスタム XML パーツ (Custom XML Part) と呼ぶ。(このファイルは、Word の利用者からは見えない。) この挿入された XML ファイルの各要素を、 上図の Content Control にバインドすることが可能であり、 Word の外のプログラムなどから、この XML ファイルの内容を更新することで、バインドされた Word 文書上の Content Control の内容を変更できる。 例えば、外部のシステムから送られてくる発注データの XML をそのまま使って、 Word 文書と連携させることができる。(SOA によるシステム間連携のシナリオ、など)

もちろん、Office Open XML (OOXML) を使って、直接 Content Control の値 (データ) を変更しても良いが、 このバインドを使った方法だと、 データ (すなわち、XML ファイル) とビュー (Word 文書) のデザインを切り離して管理できるわけだ。プログラムは、 特定の Custom XML Parts と連携するように作っておけば、 Word 文書のほうは自由に変更して構わない。また、単一の Custom XML Parts から複数の Content Control にもバインドできるため、Word 文書内で項目を関連付けておくことができる。

事前準備

OOXML を使って Custom XML Parts を挿入したり、Content Control とバインドする方法は、実は Microsoft Word には提供されていない。この処理をおこなう正統派の方法は、プログラミングだ。C# には、OOXML を含むパッケージ フォーマットのファイルを扱うライブラリーがあり (System.IO.Packaging 名前空間のクラス)、 このライブラリーを使うことで、こうした処理が可能だ。 もちろん、.docx ファイル (実体は .zip) を展開して、手動で zip ファイルの中身を編集しても良いが、 やってもらうとわかるが、相当きつい。(関連する定義が複数の場所に書かれていて、これらをすべて正しく編集しないと Word で開けなくなる。)

そこで、実は、CodePlex に、こうした編集を簡素化できるツールが提供されている。以下のツールをインストールしてみてほしい。

[CodePlex] Word Content Control Toolkit
http://dbe.codeplex.com/

例えば、独自の XML ファイルを Custom XML として挿入した Word 文書 (.docx) を、 Word Content Control Toolkit で参照すると、以下の通りだ。右ペインに Custom XML の内容が表示され、 左ペインには Word 文書に挿入している Content Control が表示される。

ContentControlToolkit

左の Content Control と右の XML の要素をバインドするには、 右ペインを [Bind View] に切り替え、 右の要素から左の要素にドラッグ・アンド・ドロップをおこなう。下図は、右 (Custom XML) の「Name」と、左 (Content Control) の「Name」をバインドさせた場合だ。下図の通り、 左ペインには、バインドしている Custom XML の XPath が表示される。

Bind

動作はご想像の通り、Word 文書内を変更するとリアル タイムに Word 内部の XML (Custom XML Part) が変更され、 逆に、プログラムなどを使って XML を変更すると、リアル タイムに Word 文書が変更される。

Execute1

開発手法 – Add-in for Word の Programming

では、この Custom XML を使用した簡単な Office Add-ins のプログラムを記述してみよう。 今回の Office Add-in では、「Bing Maps の Geocode、逆 Geocode のプログラミング」で紹介したプログラミングを使って、Bing Maps を使って地図をクリックすると、その住所を取得して、上記の Custom XML に設定する簡単なサンプル コードを作成する。すなわち、Bing Maps をクリックすると、下図の Word 文書の住所欄が、選択された住所に変更される。
Execute2

このプログラムは、下記のようなコードになる。(Office Add-ins のプログラミング手法については、上記の @IT の記事を参照してほしい。)

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
  <script src="http://ajax.aspnetcdn.com/ajax/jquery/
    jquery-1.9.0.min.js"></script>
  <script src="http://appsforoffice.microsoft.com/lib/1.0/hosted/
    office.js"></script>
  <script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?
    v=6.3&mkt=ja-jp"></script>
  <script>
  Office.initialize = function (reason) {
    $(document).ready(function () {
      map = new VEMap('map');
      map.LoadMap();
      map.SetCenterAndZoom(new VELatLong(35.70, 139.7), 13); 
      map.AttachEvent("onclick", function (e) {
        // execute when right click !
        if (!e.rightMouseButton)
          return;

        $('#msgline').html('getting location ...');

        // Get latlong
        var lat;
        if (e.latLong) {
          lat = e.latLong;
        } else {
          var pxl = new VEPixel(e.mapX, e.mapY);
          lat = map.PixelToLatLong(pxl);
        }

        // Push a pin 
        map.Clear()
        var shape = new VEShape(VEShapeType.Pushpin, lat);
        map.AddShape(shape);

        // Reverse-geocode 
        map.FindLocations(lat, function (loc) {
          if (loc != null && loc.length > 0) {
            Office.context.document.customXmlParts.getByNamespaceAsync(
              "TestNS1", function (resXml) {
              var xmlPart = resXml.value[0];
              xmlPart.getNodesAsync(
                '/ns0:EmployeeInfo[1]/ns0:Address[1]',
                function (resNode) {
                resNode.value[0].setXmlAsync(
                  '<Address xmlns="TestNS1">'
                  + loc[0].Name
                  + '</Address>');
              });
            });
          }
        });

        $('#msgline').html('location changed !');
      });

      $('#msgline').html('ready !');
    });
  };
  </script>
</head>
<body>
  <div id="map" style="position:relative;width:250px;height:400px;"> 
  </div>
  <p id="msgline" style="background-color:gray;">initializing ...</p>
</body>
</html>

上記のコードで、XPath (/ns0:EmployeeInfo[1]/ns0:Address[1]) として「ns0」の Prefix を暗黙裡に使用しているが、 実際のプログラミングでは、xmlPart.namespaceManager.getPrefixAsync を使って、割り当てられた Prefix を取得したほうが良い。(いちおう、ns0、ns1、ns2 という具合に、 順番に割り当てられる。今回は、さぼって書いている。)

なお、Office Add-ins の JavaScript API では、上記の通り、Custom XML データの入出力はできるが、バインドができないため注意が必要だ。つまり、C# でプログラミングする場合に可能であった Custom XML データの変更イベントの取得などは、この JavaScript API では不可能だ。(ただし、Node 自体の Insert、Delete、Replace のイベントをとることは可能だ。)

また、今後修正されるかもしれないが、今 (Preview 2 では)、上記のプログラムの通り、変更箇所に XML 名前空間の定義 (xmlns) を明示しておかなければいけないようだ。(これを省略すると、setXmlAsync メソッドが、名前空間としてブランクを設定するため。)

xmlns=”TestNS1″>Some address text

これに限らず、まだ、いくつか制限があるようなので、実際のプログラミングでは注意してほしい。

なお、Visual Studio を使うと、こうしたドキュメント テンプレートを使用した開発の場合に、下図の通り、ドキュメントを指定してデバッグ実行できる。Office Add-in のプログラミングは、PHP、Ruby、Node などサーバー側の開発言語に依存せず同じように書ける点が魅力だが、 上記の記事にも記載した通り、実際、「開発レベル」のプログラミングの場合には VS を使っておいたほうが無難だ。(逆の言い方をすれば、VS 以外で作ろうとすると、デバッグが結構きつい。。。)

VSDebug

Document Driven Office Add-in (まとめ)

今回は Custom XML を介してドキュメント連携をおこなったが、Add-in for Word では HTML や OOXML を挿入できるので、 例えば、Word 文書にイメージ ファイルなどのマルチメディア情報を挿入することもできる。(ただし、OOXML を使って文書のフルカスタマイズができるわけではないので注意してほしい。OOXML を使って Add-in の JavaScript API でできることは限られている。)

また、上記を応用して、SharePoint との連携も可能だ。 一般に、Word 文書と SharePoint のドキュメント ライブラリーに保存するプロパティを連携させる場合には、クイック パーツ (Quick Parts) が使用されるが、これも基本的には上記と同じ仕組み (Custom XML) を使った実装だからだ。(SharePoint のプロパティは、CustomXML の http://schemas.microsoft.com/office/2006/metadata/properties 名前空間の、documentManagement 要素に入っている。)
SharePoint の Content Type を作成して、この Content Type の document template (Word 文書) を取得すると、既に Custom XML が設定されているので、この Custom XML と連携して動作する Office Add-in を上記の通り構築し、 この Add-in を貼り付けた Word 文書 (.dotx, .docx) を、この Content Type の document template として設定しなおせば良い。

なお、SharePoint 2013 で Content Type の既定の document template を取得するには、 その Content Type を使用した Document Library を作成して、 エクスプローラー ビュー (Explorer View)、または、 SharePoint Designer から参照 (「すべてのファイル」から参照) することで、 テンプレート (template.dotx) を取得できる。

さらに、こうしたテンプレートを含んだリスト定義そのものを SharePoint Add-ins (旧 Apps for SharePoint) として配布することもできるだろう。

広告