XPCOM を使ってクライアント・サイドで OpenOffice 文書を動的に生成する

サーバーに依存しない、移植性とコスト効果の高い代替手段

Mozilla の XPCOM (Cross Platform Component Object Model) フレームワークを利用すると、既存の XML コンテンツを OpenOffice 文書へと動的にエクスポートすることができます。このプロセスは、XSLT などの変換メカニズムでサポートされている他の任意タイプのコンテンツの場合も同様に機能します。この記事では、サーバー・サイドのソリューションに代わる、移植性とコスト効果の高いソリューションについて学びます。

Stefanus Wiguna , Advisory Software Engineer, IBM

Stefanus Wiguna Stefanus Wiguna はノースキャロライナ州 Research Triangle Park にある IBM Software Group のアドバイザリー・ソフトウェア・エンジニアです。彼は Principal Certified Lotus Professional であり、Lotus、Web 2.0、Java 技術を使ったソリューション開発と統合に 10 年以上の経験があります。



2009年 7月 07日

はじめに

OpenOffice は、高価な商用オフィス・ソフトウェア・スイートに代わるオープンソースのオフィス・ソフトウェア・スイートとしてよく使われるようになっています (しかも、無料です)。ただしコンテンツの作成や、既存のコンテンツを OpenOffice へとエクスポートする作業は、適切なツールがないと非常に面倒です。

通常、OpenOffice 文書を動的に作成したり、既存のコンテンツを OpenOffice 文書へと動的にエクスポートしたりするためには、以下の作業を行う必要があります。

  • サーバー上で実行されている Web アプリケーションによって、対象そのコンテンツを ODF (OpenDocument Format) に変換します。
  • 変換されたコンテンツを OpenOffice 文書アーカイブに圧縮します。
  • そのファイルを保存するか、あるいはユーザーに提供します。

しかし、サーバー・サイドのアプリケーションを利用できない場合にはどうするのでしょう。あるいは、このプロセスをクライアントに移すことで単純にサーバー負荷を最小にしたい場合にはどうするのでしょう。

この記事では、XPCOM、Firefox 拡張機能、OpenOffice、OpenDocument Format、XSLT についての詳細な説明は省略します。これらの話題に関する詳細は「参考文献」を参照してください。

この記事では、Mozilla の XPCOM (Cross Platform Component Object Model) フレームワークを使ってアプリケーションを迅速に開発する方法を学びます。また、例を通して、Firefox 拡張機能の中で XPCOM コンポーネントを使って、既存の XML コンテンツを OpenOffice 文書へと動的にエクスポートする方法を説明します。この方法の使い道は XML のエクスポートのみに限定されているわけではありません。他のタイプのコンテンツも、そのコンテンツが (XSLT (Extensible Stylesheet Language Transformations) などの) 変換メカニズムでサポートされている限り、同じ方法で処理することができます。

実際にコンテンツを動的に OpenOffice へとエクスポートする前に、次のセクションで OpenOffice 文書を作成するための要件について説明します。


OpenOffice 文書

基本的に、OpenOffice 文書は圧縮されたファイルであり、ある文書のさまざまな部分 (コンテンツとスタイル、マニフェスト、サムネイルなど) を記述する一連の XML ファイルで構成されています。

図 1 は、OpenOffice テキスト文書 (.odt) を取得して .zip 拡張子を付けてリネームし、それを解凍した場合のファイル構造を示しています。

図 1. OpenOffice 文書の構造
OpenOffice 文書の構造

表 1 はいくつかのファイルを簡単に説明したものです。

表 1. OpenOffice 文書のファイル
ファイル説明
content.xmlその文書の実際のコンテンツを含んでいます。
meta.xmlshi a shi作成日や著者などのメタデータ情報を含んでいます。
styles.xml段落や文字などのフォーマット・スタイルを定義します。

新しい OpenOffice 文書を作成する上で最も容易で最も安全な方法は、既存の文書を編集する方法です。この記事では、文書の実際のコンテンツが保存されている content.xml のみを更新します。content.xml 自体は図 2 のようなものです。

図 2. OpenOffice 文書の content.xml
OpenOffice 文書の content.xml

この記事の例では、実際のコンテンツの前にあるセクションを content head と呼ぶことにし、実際のコンテンツの後にあるセクションを content tail と呼ぶことにします。実際のコンテンツ自体は content body です。新しい OpenOffice 文書を作成する際には、必ずこれらのセクションを使います。


開発環境を準備する

OpenOffice へとエクスポートするためには、Firefox 拡張機能の開発環境の中でいくつかのことをする必要があります。ここでは既存の OpenOffice 文書を編集して新しい OpenOffice 文書を作成するため、次のことをする必要があります。

  1. 図 1 の中にあるすべてのファイルを Firefox 拡張機能のパッケージの中に含めます。これらのファイルを使って新しい OpenOffice 文書を作成します。
  2. これらのファイルを Firefox 拡張機能のクローム・フォルダーの外に保存します。こうすれば、拡張機能のパッケージング中にファイルが圧縮されることがなく、後でファイルを容易に取得できるようになります。

Firefox 拡張機能の内部にどのような構造でファイルが保存されているのかを示したものが下記の図です。

図 3. Firefox 拡張機能の構造の中での OpenOffice 文書ファイル
Firefox 拡張機能の構造の中での OpenOffice 文書ファイル

OpenOffice 文書のファイルはすべて同じフォルダーに保存することができます。OpenOffice 文書を作成する際には、アーカイブの中の適切な場所に各ファイルを置きます。xml2odt.xsl は既存のコンテンツを ODF に変換するために使うカスタムのスタイルシート・ファイルです。

次のステップでは、いくつかの変数と定数を設定します。これらの変数と定数は、OpenOffice 文書を生成するプロセス全体で行われるファイル操作 (ファイルの検索や取得など) で使われます。リスト 1 はその一例です。変数と定数の設定には XPCOM の nsIExtensionManager インターフェースを使用します。

リスト 1. 変数と定数を設定する
var eid = "export2OO"; // extension id
var em = Components.classes["@mozilla.org/extensions/manager;1"]
 .getService(Components.interfaces.nsIExtensionManager);

var oopath = "export/oo/"; // path to the OpenOffice document files
var ooxslt = "xml2odt.xsl";

const PR_WRONLY = 0x02;
const PR_RDWR = 0x04;
const PR_CREATE_FILE = 0x08;
const PR_APPEND = 0x10;
const PR_TRUNCATE = 0x20;
const PR_USEC_PER_MSEC = 1000;
const time = Date.now();

この記事のコードはすべて、Firefox 拡張機能がアクセスできる場所でありさえすれば、任意の場所に置くことができます。通常は、クローム・フォルダーの中にある JavaScript ファイル (.js) の中にコードを保存し、その JavaScript ファイルを Firefox 拡張機能のメインの XUL ファイルの中に含めます (リスト 2)。

リスト 2. Firefox 拡張機能の中にコードを含める
<overlay id="export2OO"
 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 <script type="application/x-javascript;version=1.7"
           src="chrome://export2OO/content/export.js" />

これで開発環境が準備できたので、次のセクションでは実際に文書を作成します。


OpenOffice 文書をプログラムで作成する

既存のコンテンツを OpenOffice 文書へと動的にエクスポートするための主なタスクには、次の 3 つがあります。

  • 既存のコンテンツを OpenDocument フォーマットに変換する
  • その新しいコンテンツを使って新しい OpenOffice 文書を作成する
  • 新しく作成された OpenOffice 文書を自動的に起動する

既存のコンテンツを OpenDocument フォーマットに変換する

XSLT (Extensible Stylesheet Language Transformations) を使用すると、既存のコンテンツを容易に ODF に変換することができます。例えばリスト 3 は、XML フォーマットでのコンテンツの一部を示しています。

リスト 3. XML で表現したコンテンツ
<h1>This is Heading 1</h1>
<h3>This is Heading 3</h3>

リスト 4 は同じコンテンツをODF で表現したものです。

リスト 4. ODF で表現したコンテンツ
<text:h xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
 text:style="Heading1" text:outline-level="1">
 This is Heading 1
</text:h>
<text:h xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
 text:style="Heading3" text:outline-level="3">
 This is Heading 3
</text:h>

ODF 仕様には、スタイルの定義とフォーマットに関するあらゆる情報が提供されています (「参考文献」を参照)。スタイルシート・ファイルが用意できると、Firefox 拡張機能の環境の中で変換を実行することができます。そこで、拡張機能マネージャーを使用して、変換に使用するスタイルシート・ファイルを見つけます。リスト 5 はその例を示しています。

リスト 5. XSLT ファイルを見つける
// locate stylesheet file
var xslfile = em.getInstallLocation(eid).getItemFile(eid, oopath + ooxslt);

次に、このスタイルシート・ファイルをロードします。

リスト 6. XSLT ファイルをロードする
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
 .createInstance(Components.interfaces.nsIFileInputStream);
var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"]
 .createInstance(Components.interfaces.nsIScriptableInputStream);

var xsldata = "";
fstream.init(xslfile, -1, 0, 0);
sstream.init(fstream); 
var tmp = sstream.read(4096);
while (tmp.length > 0) {
 xsldata += tmp;
 tmp = sstream.read(4096);
}
sstream.close();
fstream.close();

var parser = new DOMParser();
var xsldoc = parser.parseFromString(xsldata,"text/xml");

ロードしたスタイルシートを使ってコンテンツを ODF に変換します。次の例で、xmldoc は既存のコンテンツを持つ XML 文書です。

リスト 7. XSLT を使ってコンテンツを ODF に変換する
var xsltprocessor = new XSLTProcessor();
xsltprocessor.importStylesheet(xsldoc);
var newcontentdoc = xsltprocessor.transformToFragment(xmldoc,document);

この時点で、新しいコンテンツを使って content.xml を更新します。OpenOffice のための妥当な content.xml を作成するためには、適切な content head と content tail を含める必要があります (図 2)。

リスト 8. 新しいコンテンツを使って content.xml を更新する
// prepare new content
var contentbody = (new XMLSerializer()).serializeToString(newcontentdoc);
var newcontent = xmlheader + contenthead + contentbody + contenttail

// update content.xml
var contentfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "content.xml");
var fstream = Components.classes["@mozilla.org/network/file-output-stream;1"]
 .createInstance(Components.interfaces.nsIFileOutputStream);
fstream.init(contentfile, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0666, 0);
fstream.write(newcontent, newcontent.length);
fstream.close();

これで content.xml が更新されました。次のセクションでは、新しい OpenOffice 文書を作成します。

OpenOffice 文書を作成する

新しい OpenOffice 文書を作成するためには、新しい OpenOffice アーカイブを作成し、その OpenOffice アーカイブに content.xml と他の必須ファイルを追加します。この例では、そのために XPCOM の nsIZipWriter インターフェースを使っています。

最初のステップとして、アーカイブ・ファイルを作成し、それをユーザーのマシンに保存します。下記の例では、新しいファイルをデスクトップ領域に保存します (リスト 9)。要件によっては、一時ファイルを作成したり、新しいファイルを他の場所に保存したりする必要があるかもしれません。

リスト 9. 新しい OpenOffice 文書アーカイブを作成する
var odtfile = Components.classes["@mozilla.org/file/directory_service;1"]
 .getService(Components.interfaces.nsIProperties)
 .get("Desk", Components.interfaces.nsIFile);
odtfile.append("new.odt");
odtfile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666);

var zipWriter = Components.Constructor("@mozilla.org/zipwriter;1", "nsIZipWriter");
var odt = new zipWriter ();
odt.open(odtfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE | PR_APPEND);

表 2 は Desk 以外にもファイルを保存するために一般に使われるディレクトリーの値を示しています。

表 2. ファイルを保存するための一般的なディレクトリーの値
ファイル説明
ProfDFirefox のプロファイル・ディレクトリー
Deskデスクトップ・ディレクトリー (Linux® での ~/Desktop や Windows® での C:\Documents and Settings\username\デスクトップなど)
Homeオペレーティング・システムのルート・ディレクトリー (Linux の /root や Windows の C:\ など)
TmpDオペレーティング・システムの一時ディレクトリー

第 2 のステップとして、必要な OpenOffice 文書ファイルをアーカイブに追加します。各ファイルを追加する際には、図 1 に示す構造の適切な場所に追加する必要があることを忘れないでください。

リスト 10. OpenOffice 文書をアーカイブに追加する
// locate file
var contentfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "content.xml");
// add file to archive
odt.addEntryFile("content.xml", 
 Components.interfaces.nsIZipWriter.COMPRESSION_NONE,
 contentfile, false);

// create directory
odt.addEntryDirectory("META-INF", time * PR_USEC_PER_MSEC, false);
// locate file
var manifestfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "manifest.xml");
// add file to specific directory in archive
odt.addEntryFile("META-INF/manifest.xml",
 Components.interfaces.nsIZipWriter.COMPRESSION_NONE, 
 manifestfile, false);

odt.addEntryDirectory("Thumbnails", time * PR_USEC_PER_MSEC, false);
var thumbfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "thumbnail.png");
odt.addEntryFile("Thumbnails/thumbnail.png", 
 Components.interfaces.nsIZipWriter.COMPRESSION_NONE, 
 thumbfile, false);

var metafile = em.getInstallLocation(eid).getItemFile(eid, oopath + "meta.xml");
odt.addEntryFile("meta.xml", 
 Components.interfaces.nsIZipWriter.COMPRESSION_NONE, 
 metafile, false);

var mimetypefile = em.getInstallLocation(eid).getItemFile(eid, oopath + "mimetype");
odt.addEntryFile("mimetype", 
 Components.interfaces.nsIZipWriter.COMPRESSION_NONE, 
 mimetypefile, false);

var settingsfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "settings.xml");
odt.addEntryFile("settings.xml", 
 Components.interfaces.nsIZipWriter.COMPRESSION_NONE, 
 settingsfile, false);

var stylesfile = em.getInstallLocation(eid).getItemFile(eid, oopath + "styles.xml");
odt.addEntryFile("styles.xml", 
 Components.interfaces.nsIZipWriter.COMPRESSION_NONE, 
 stylesfile, false);

// close the archive
odt.close();

これで新しい OpenOffice 文書の作成が完了し、この文書を使用する準備が整ったので、この文書を起動することができます。

OpenOffice 文書を起動する

新しい文書は既にデスクトップ領域に保存されているため、自由に起動することができます。この新しい文書は、いつでも手動で開くことができ、あるいは他のプロセスの入力として使用することができます。

ファイルの関連付けが適切にされていると、下記のサンプル・コードによって、新しく作成された文書が OpenOffice で自動的に開きます。

リスト 11. OpenOffice 文書を自動的に起動する
var ios = Components.classes["@mozilla.org/network/io-service;1"]
	   .getService(Components.interfaces.nsIIOService);
var odtURL = ios.newFileURI(odt);
location.href = odtURL.spec;

ファイルの関連付けがされていないと、下記のようなウィンドウが表示されます。

図 4. OpenOffice 文書を開く
OpenOffice 文書を開く

これで、すべて完了です。

Firefox 拡張機能をビルドしてインストールすると、この記事のコードによって「OpenOffice へのエクスポート」機能をクライアント上で実現することができます。


まとめ

XPCOM のリッチなライブラリーによって、アプリケーションの開発を迅速に行えるようになり、それまではサーバー・サイドでしかできなかったことをクライアント・サイドで行えるようになります。これにより、サーバー・サイドのソリューションに代わる、移植性とコスト効果の高いソリューションを得ることができます。

参考文献

学ぶために

  • OpenOffice.org のすべてを知ってください。
  • XPCOM第1回: XPCOM入門」を読み、アプリケーションの開発をスピードアップしてください。
  • Firefox Toolbar Tutorial は Firefox ブラウザー用にツールバーの拡張機能を作成する方法を解説しています。
  • Mozilla Developer Center の Extensions には、Mozilla アプリケーション用の拡張機能を作成するために必要なすべての情報が用意されています。
  • ファイル入出力のための XPCOM インターフェース、File I/O について学んでください。
  • データ・アーカイブのための XPCOM インターフェース、nsIZipWriter の資料を読んでください。nsIZipWriter 利用すると、ZIP ファイル・フォーマットでデータをアーカイブするためのスクリプトを容易に作成することができます。
  • OpenOffice.org の XML ベース文書フォーマットを操作する」は OpenOffice 文書の構造を紹介しています。
  • OASIS の標準、Open Document Format for Office Applications (OpenDocument) を読んでください。
  • OpenDocument XML.org はコミュニティーが集まる正式な場所であり、ODF (OpenDocument Format) に関する OASIS の標準 (ISO/IEC 26300) の情報リソースです。
  • XSLT Tutorial を受講し、XSLT を利用して XML 文書を XHTML などの他のフォーマットに変換する方法を学んでください。
  • developerWorks podcasts ではソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • developerWorks を Twitter でフォローしてください。
  • IBM オープンソース開発者にとって関心のある、世界中で今後開催される会議や業界展示会、ウェブキャスト、その他のイベントについて調べてみてください。
  • developerWorks の Open source ゾーンをご覧ください。オープンソース技術を使った開発や、IBM 製品でオープンソース技術を使用するためのハウ・ツー情報やツール、プロジェクトの更新情報など、豊富な情報が用意されています。
  • IBM とオープンソース技術、そして製品機能を調べ、学ぶために、無料の developerWorks On demand demos をご覧ください。

製品や技術を入手するために

  • OpenOffice と拡張機能をダウンロードしてください。
  • XPCOM のサイトは XPCOM に関連するすべての情報を入手できる中心的な場です。
  • Firefox アドオンによって Firefox を拡張することができ、ブラウザーでのエクスペリエンスをパーソナライズすることができます。
  • 皆さんの次期オープンソース開発プロジェクトを IBM ソフトウェアの試用版を使って革新してください。ダウンロード、あるいは DVD で入手することができます。
  • IBM 製品の試用版をダウンロードするか、あるいはオンラインで IBM SOA Sandbox を試し、DB2®、Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=418075
ArticleTitle=XPCOM を使ってクライアント・サイドで OpenOffice 文書を動的に生成する
publish-date=07072009