レベル: 初級 Benoit Marchal (bmarchal@pineapplesoft.com), Consultant, Pineapplesoft
2002年 4月 01日 今回は、「実用的なXML」で3番目のプロジェクトを開始します。この新しいプロジェクトでは、XML公開ソリューション (またはそのための任意のXMLソリューション) へのテキスト文書のインポートを扱います。
2文字の省略名を使用するという今までの命名法を踏襲して、新しいプロジェクトにはXIという名前を付けます。これは「XML Import」の略です。XIでは、XML文書としてテキスト文書をインポートするための簡単なソリューションを実現します。このソリューションは、以前の記事で紹介したXSLT Maker (XM) と組み合わせると、テキスト文書を公開チェーンの一部として処理できるので特に便利です。具体的には、XMで保守されているWebサイトに住所リストをインポートすることを考えています。
もちろん、XIには他にも使い道があります。テキスト文書をXMLに変換する必要があるときにはいつでも役に立ちます。これには、e-commerceや同様のプロジェクトが含まれます。これらの場合についても記事の中で言及するつもりです。
XMLと他のデータ
多くの点において、XMLは非常に短い時間で信じられないほどの成功を収めてきました。W3CがXML 1.0をリリースしてからわずか4年にして、XMLのことを少しも知らないという開発者を見つけるのが困難なほどです。同様に、何千もの語い (つまりXMLスキーマ) とそれに勝る数のアプリケーションが開発されています。
依然として、多くのプロジェクトでは、データの一部または全部が元の形式ではXMLで利用できないという状況が見られます。最近のアプリケーションは1次ファイルのフォーマットとしてXMLを採用していますが、古いアプリケーションは他のフォーマットに依存しているので、多くの場合、新しいフォーマットと古いフォーマットのデータが混在することになります。
住所録とWebサイト
この記事で最初にXMを公表して以来、弊社で運用しているサイトの一部では、公開作業の中でXMを使用しています。最近のあるプロジェクトは、XMLと他のファイルの共存について説明する格好の実例です。そのサイトは、数年にわたって続いているプロジェクトをサポートしています。その間、プロジェクトには多くの文書が蓄積されており、その大部分はWordのフォーマットです。これらの文書はアーカイブの一部なので、XMのディレクトリー読み取りを使って単純にリンクさせています。
それでも、Webサイトにインポートする必要のあるファイルがわずかですが存在します。そのようなファイルの1つがプロジェクト関係者のリストで、現在はリスト1 のようなテキスト文書 (ここでは名前と住所は架空のものです) として保持されています。
この記事の内容とは関係のないさまざまな理由のため、リストは当面は同じフォーマットのまま保持されます。それでも、関係者の最新のリストを、できれば電子メール・アドレスへのハイパーリンクを含むHTML文書として公開する必要があります。XMLで同じリストを作成するのも1つの解決策ですが、リストは頻繁に変更されるので、できればそれは避けたいと考えています。保守作業が頭痛の種になる可能性がありますから。
元の文書をXMにそのまま渡すことはできないので、XMLへの変換を自動的に行うことにしました。処理を自動化できさえすれば、常に最新のバージョンをオンラインで確実に提供できます。副次的な利点として、このプロジェクトを思いつくこともできました。
XMLのインポートについて
幸いにも、この問題は著者にとって目新しいものではありません。コンサルタントとしての仕事のほとんどは、e-commerceに関係するものでした。e-commerceの最も古い形式の1つであるEDI (電子データ交換) を手始めに、オンライン・ショップやXML Webサービスへと進んできました。
e-commerceについて最初に習うことの1つは、無数にあるファイルをどう扱うかです。標準的なe-commerceアプリケーションは、以下のような機能を備えているので、企業内のほとんどすべてのアプリケーションとのインターフェースを持つ必要があります。
- 商品の説明と価格の情報をカタログから収集する。
- 場合によっては、倉庫から商品の納期情報を収集する。
- ビジネス管理機能とインターフェースを取り、注文の処理を行って送り状を作成する。
- 支払いや他の情報のために会計機能とやり取りする。
企業間の対話の場合は、必然的に、自社のバック・オフィスだけでなくパートナーのバック・オフィスとも統合を試みるので、多数のファイルを扱う事態はさらに多く発生します。
関連情報はすべてDB2データベースに収められ、すべてのアプリケーションは明確に定義されたAPIを備えていれば理想的です。しかし残念ながら、実際には、最も必要なフォーマットでデータを利用できることはほとんどありません。
たとえば、カタログ・データは独自のデータベースにしまい込まれていて、顧客リストはデータベースをエクスポートできる可能性の低い単純なPIMで保持されている場合があります。あるいは、バック・オフィスが社内で開発されていて、元の設計から大きく拡張されている場合もあります。
このような分野においても、XIの有効な利用対象が見つかる可能性があります。しかし、この記事の目的を考慮して、関係者リストのインポートだけに話を絞ります。
インポートとXSL
ここ2年ほどの間、著者は、ハイエンドのソリューションからもっと手ごろなものまで、さまざまなツールを使ってこれらの文書を処理してきました。また、アプリケーションの担当部分を作成してきて、構文コンバーターを利用して補強することでXSLTが非常に魅力的なソリューションを提供することに何度も気付かされました。
インポート処理は、構文変換と、データ構造の再構成という2つのステップに分けると都合がよいことがわかりました。構文変換では、文字情報を取り出し、それを最も単純なXML構造にラップします。通常、できあがったXML文書は、元の文書と非常によく似ています。ほとんどの場合は、区切り文字をXMLタグに置き換えた程度の単純さです。
第2のステップでは、XSLTを使って、この未完成のXML文書を対象の語彙に変換します。このようにステップを2つに分けることは特に有用で、以下のような利点があります。
- コードが2つのモジュールで構成されるので、保守が一層容易になります。
- 各モジュールは、処理に最適なツールで記述されます。Javaのようなシステム・プログラミング言語は構文変換に理想的であり、XSLTのようなスクリプト言語は再構成に最適です。
- スタイル・シートの作成はJavaでのコーディングより比較的簡単なので、経験の浅いチーム・メンバーに作業を割り当てることができます。
- 構文コンバーターとスタイル・シートは、どちらも、通常は、別の文書に対して再利用できます。
ただし、このプロジェクトの場合は、テキスト文書が非常に特殊なフォーマットであるため、ほとんど再利用できないものと考えられます。それでも、新しいJDK 1.4では正規表現 (regex) に対するサポートが追加されており、もう少し一般的なソリューションを開発するには、それを使用すると便利であると思われます。
正規表現に不慣れな場合は、O'Reillyから出版されているMastering Regular Expressions を参照してください (参考文献を参照)。一言でいうと、正規表現とは文字列のパターンを記述したものです。正規表現エンジンを使えば、ある文字列がそのパターンに一致しているかどうかを簡単に検査できます。入力の妥当性を検査したり、パターンが一致した場所で文書を分割したりする場合に役に立ちます。
上位レベルの仕様
XIについての理解を深めるには、リスト2の内容を吟味してみてください。リスト2には、リスト1を解釈する正規表現が記述されています。最終的に、XIは、ここで記述されている式を使って、リスト1をリスト3に変換します。リスト3はXML文書です。
リスト2. XIの記述ルール
<?xml version="1.0">
<xi:rules version="1.0"
xmlns:xi="http://ananas.org/2002/xi/rules"
xmlns:an="http://ananas.org/2002/sample">
<xi:ruleset name="an:address-book">
<xi:match name="an:alias"
pattern="^alias "([^"]*)" (\S*)$">
<xi:group name="an:id"/>
<xi:group name="an:email"/>
</xi:match>
<xi:match name="an:note"
pattern="^note "([^"]*)" (\S*)$">
<xi:group name="an:id"/>
<xi:group name="an:fields"/>
</xi:match>
<xi:error msg="unknown line type"/>
</xi:ruleset>
<xi:ruleset name="an:fields">
<xi:match name="an:field"
pattern="<(\s):(\s)>">
<xi:group name="an:key"/>
<xi:group name="an:value"/>
</xi:match>
</xi:ruleset>
</xi:rules>
|
リスト1とリスト2は、XIの動作を筆者が理解するための助けに作成したものであり、単なる例とお考えください。これらは必ずしも最終的な文書ではありません。XIを開発する過程で、これらの文書に対して若干の修正が必要になる可能性があります。
リスト3. XIが生成する文書のサンプル
<?xml version="1.0"?>
<an:address-book xmlns:an="http://ananas.org/2002/sample">
<an:alias>
<an:id>jdoe</an:id>
<an:email>jdoe@xmli.com</an:email>
</an:alias>
<an:note>
<an:id>jdoe</an:id>
<an:fields>
<an:field>
<an:key>country</an:key>
<an:value>US</an:value>
</an:field>
<an:field>
<an:key>zip</an:key>
<an:value>45202</an:value>
</an:field>
<an:field>
<an:key>state</an:key>
<an:value>OH</an:value>
</an:field>
<an:field>
<an:key>city</an:key>
<an:value>Cincinnati</an:value>
</an:field>
<an:field>
<an:key>address</an:key>
<an:value>34 Fountain Square Plaza</an:value>
</an:field>
<an:field>
<an:key>name</an:key>
<an:value>John Doe</an:value>
</an:field>
</an:fields>
</an:note>
<an:alias>
<an:id>jsmith</an:id>
<an:email>jsmith@worth-it.com</an:email>
</an:alias>
<an:note>
<an:id>jsmith</an:id>
<an:fields>
<an:field>
<an:key>first</an:key>
<an:value>Jack</an:value>
</an:field>
<an:field>
<an:key>last</an:key>
<an:value>Smith</an:value>
</an:field>
<an:field>
<an:key>name</an:key>
<an:value>Jack Smith</an:value>
</an:field>
</an:fields>
</an:note>
<an:alias>
<an:id>pdupont</an:id>
<an:email>pdupont@pineapples.net</an:email>
</an:alias>
<an:note>
<an:id>pdupont</an:id>
<an:fields>
<an:field>
<an:key>name</an:key>
<an:value>Pierre Dupont</an:value>
</an:field>
</an:fields>
</an:note>
</an:address-book>
|
リスト3のフォーマットはできる限り簡単にしました。記述は、1つ以上のルールセットで構成されています。各ルールセットでは、入力が一致しなければならないパターンのリストが指定されています。XIは、入力をこれらのパターンのそれぞれと突き合わせて、最初に一致したパターンに関連付けられている記述を適用します。
パターンの中で、括弧はグループを表しています (リスト2 を参照)。各グループは、異なるXML要素に一致する場合があります。
パターンが一致すると、XIは、1つ以上のXML要素を生成するか、または別のルールセットに移行します。これは、一部のパターンはさらに分解する必要がある、という考え方に基づいています。リスト1 においてnotes "jdoe" で始まっている注釈行は格好の例です。注釈行には不定数のフィールドが含まれており、正規表現でこのような行が識別されたら、それをさらにフィールド単位に分解する必要があります。
属性は、リスト2 の全体を通して一貫しています。name属性は出力におけるXML要素の1つを表しており、ruleset、match、およびgroupに適用されます。call属性は、別のルールセットを使ってグループをさらに分解する必要があることを示しています。
このフォーマットには、意図的に制限を設けてあります。たとえば、XIは要素だけを生成し、属性は生成しません。すべてのruleset、match、およびgroupに要素を関連付ける必要があります。目標は、このフォーマット (およびXI) をできる限りシンプルにしておくことです。より高度な記述言語を作成するよりも、文書を再編成したり、要素を属性に変更したり、XSLTでタグを省略したり挿入したりする方がずっと簡単です。
この場合、DocbookのXI出力を生成するのは、リスト4 のようなスタイル・シートの役目です。このスタイル・シートは最適化する前の状態であり、説明のためだけに使用していることに注意してください。
XPathsとXSLT 2.0
XIは、XPath 2.0 (したがってXSLT) に対して提案されている正規表現の追加機能とは異なるものです。また、Simon St LaurentのRegular Fragmentationライブラリー (参考文献を参照) とも異なります。筆者が素案について理解した限りでは、XPath 2.0はパターンを使って要素を分解しているようです。しかし、入力文書は既にXML文書になっているという前提は、残されたままです。
それに対し、XIは、正規表現を使ってテキスト文書をXMLに変換します。あるいは、むしろ、2つのソリューションは相補的な関係にあります。XIを使ってXML文書を用意し、XPath 2.0を使用するスタイル・シートにそれを渡して特定の情報の断片を選択するのが、意味のある方法であると考えられます。
分析
ここでは、XMを簡単に分析して、これまでの解説を補足します。
XMLReaderのインプリメント
XMLの変換を最初に試みたときには、一時ファイルを作成し、それをXSLTコンバーターに渡していました。そのため、不本意ながら、文書をディスクに書き込んで再びそれを読み取っていました。その後、途中の構文解析を省略し、コンバーターからSAXイベントを直接生成する方法を学びました。XMの開発の際には、この技法をDirectoryReaderに組み込みました。
さらにその後、XMLReaderインターフェースをインプリメントする方が一層有効であることを発見しました。XSLTで文書を後処理するときには、javax.xml.transform.sax.SAXSourceがパラメーターとしてXMLReaderを受け付けるので、特にこの方法が有用です。
クラス図
下の図1は、XIのクラス図です。メイン・クラスはXIReaderで、XMLReaderをインプリメントしています。このクラスは、定義に従ってテキスト文書の構文解析を行い、正規表現を適用し、適切なSAXイベントを生成します。
JDKには正規表現ライブラリーが含まれているので、このクラスに関して問題点はないものと考えられます。setProperty() を使ってXIReaderに文書記述 (リスト2 と同様のもの) を渡す必要があります。XIReaderは、RulesHandlerを使って文書記述をデコードします。RulesHandlerはSAXのコンテンツ・ハンドラーなので、HCが便利だと思います。図を見るとわかるように、クラスはHCHandlerを継承しています。
最後に、文書記述を保持するクラスがいくつかあることがわかります。リスト2で使われているError、Group、Ruleset、およびMatchの各タグについては、リスト2に対応するクラスが存在しています。Rules要素が必要かどうかは、まだ検討中です。Rules要素を導入したとしても、図1が大きく変わることはありません。
図1. XIのクラス図
クラスはすべてorg.ananas.xiパッケージで定義されています。
次回の予定
今回は、XIの分析と要件について解説しました。次回は、XIReaderの最初のバージョンでプロジェクトのインプリメントを始める予定です。いつもと同じように、コードはオープン・ソース・ライセンスでリリースします。
参考文献
著者について  | 
|  | Benoit Marchal氏は、ベルギーのナミュールを拠点にしたコンサルタントおよび著述家です。彼の著作には、 XML by Example(Que社、邦訳: インプレス社「実例で学ぶXML」。間もなく第2版が出版される予定です)、 Applied XML Solutions および XML and the Enterprise があります。また、Gamelanのコラムや、developerWorks XML zoneのコラムWorking XML の著者でもあります。最新プロジェクトの詳細については、www.marchal.com をご覧ください。 |
記事の評価
|