japan.internet.com The Internet & IT Network


RSSニュース検索
カテゴリ
> トップページ
> Webビジネス
> Eコマース
> Webファイナンス
> Webマーケティング
> パブリック
> Webテクノロジー
> 携帯・ワイヤレス
> Linux Today
> Linux Tutorial
> J.I.C.ブログ
キャリア
> 転職ならen
> 派遣ならen
> アルバイトならen
> IT求人情報
ヘッドライン
> 今日のヘッドライン
> 週間ヘッドライン
Special Link
> フォトコミュニティ
> ストックフォト
> クリップアート
> イラスト
> フェリカ
> Web2.0
> 写真
イベント&セミナー
> イベントカレンダー
> 書評「IT の耳」
> 出張・接待検索
> ニュースガジェット 注目
無料ニュースメール
> 新規登録
> 変更・解除
> オプトインメールの登録・変更・解除
インフォメーション
> パートナーサイト
転職ならエン
就職ならen
求人ならen
履歴書ならen
アルバイトならエン
CRM/SFAならオラクル
> グループ会社
株式会社アエリア
(株)サンゼロミニッツ
株式会社エアネット
> お問い合わせ
> 広告掲載について
> リンクについて
> 著作権について
> その他お問い合わせ
> 利用規約
> 個人情報保護方針
> 会社概要地図
コラム コラム一覧へ戻る

japan.internet.com 編集部 japan.internet.com 編集部
米国 Jupitermedia が運営する、
企業向けアプリケーションの開発者向けの技術情報/サービスサイト。


 メール  著者にメールする
 ホーム  http://www.devx.com/

最新コラム

XMLデータストリームの検証を動的プロセスにする

著者: Kurt Cagle プリンター用 記事を転送
2008年4月29日 10:00 付の記事
■海外internet.com発の記事

はじめに

 XML Schemaのもともとの目的は、XMLの検証および定義をDTD(文書型定義)よりも優れた方法で行うためのレイヤを提供することでしたが、その根本にあったいくつかの概念はいつのまにか変化しました。そうした概念の1つが、「属性は列挙(リスト)に設定できるが、その列挙はスキーマ自体の中に指定する必要がある」というものです。XMLが分散化するに従って、また、データ構造が複雑化して静的な定義だけでなく動的な定義にも依存するようになるに従って、開発者たちは、そうした動的な定義を自分自身でサポートするスキーマ言語を使う必要があると認識するようになりました。

 ISO SchematronはXPath 2.0(特にdoc()やunparsed-text()のような関数)を利用できるようになったため、ビジネスコンテンツのためのクリティカルな「分散検証」言語であると考えていいかもしれません。Schematronの詳細については後述しますが、私は以前、Nordstromという高級衣料品販売業者のためにコンサルタントとしてプログラミングを行っているときに、Schematronが非常に適していると思われる用途を色々思いつきました。

 その頃、私はWeb経由のデプロイメントを通じて、仕入先から送られてくるインボイスを検証・表示・編集するメソッドを開発していました。当時はEDI標準が徐々に姿を消し、何らかの形式のXMLに向かっている時期でした(ebXMLが完成してまだ1年というところでした)。私はXMLに気持ちが傾いていたので、使えそうなツールをあれこれ引っ張り出してきて――新たに登場したXML Schemaもそこに含まれていました――XSD(XML Schema Difinition)を使ってインボイスのモデル化を始めました。ほとんどのインボイスは非常にすっきりとマッピングできました。若干難しかった点は、処理対象の店舗のIDを検証して正しいことを確認する必要があったことです。

 この問題は簡単に解決できそうに見えるかもしれません。単に、一連の店舗をスキーマの<xs:enumeration>要素で列挙すればいいだけの話ではないのでしょうか? しかし、Nordstromはそのころ整理統合を進めている最中で、毎週のように店舗が閉鎖されていました。正規表現と比較することにすれば、そうした要件が要らなくなると思うかもしれません。しかし、それではうまくいきません。検証をする大事な理由の1つは、問題の店舗が正当なものであり、なおかつ閉店していないことを確認することだからです。結局開発したのはその場しのぎのソリューションでした。つまり、サーバー自身がデータベース呼び出しから直接取得したリストを使ってXMLを後処理するという方法です。

 それからしばらく経ったのち、スキーマで生成されたXFormsを扱っているときに、同じ問題がまた浮かび上がってきました。そこで、リストの性質とリストとモデルとの関係について色々と考えました。最も根本的なところでは、すべてのリストには詰まるところ2つの共通点があります。1つは、リストはオブジェクトのシーケンスであるということです。もう1つはもっと重要で、リストの各オブジェクトには、それに対する一意のキーがあって、それがリスト内でオブジェクトを識別しているということです。インデックス化された領域の場合、キーとはアイテムの位置を識別するための番号です(通常は0または1がベースになります)。したがってアイテムの名前(キー)が一意なのはその配列(リニアな配列)のコンテキスト内に限られ、その配列において、その番号に至るまでのシーケンスが変わらない場合だけです。

 たとえば、次のような色リストのサンプルで考えてみましょう。

colors = ['red', 'orange', 'yellow', 'green', 'blue', 'violet']
 このリストに番号キーを付けて、シーケンシャルなリストであると明示することもできます(概念的には同じものです)。

colors = {0 : 'red', 1 : 'orange', 2 : 'yellow', 
          3 : 'green', 4 : 'blue', 5 : 'violet'}
 この形式にすると、次のようにインデックスを使って特定のリソースに効率よくアクセスできるようになります(同様の方法で、インデックスで指定したエントリに値を代入することもできます)。

print colors[0]
=> red
colors[0] = 'scarlet'
print colors[0]
=>scarlet
 これに対して、連想配列では、リスト内で正式な名前に参照用の名前を関連付けます。

colors = {rd : 'red', or : 'orange', ye : 'yellow', 
          gn : 'green', bu : 'blue', vi : 'violet'}
 これにより、関連付けられた参照用の名前を使って、配列の特定の要素にアクセスできます。

print colors['rd']
=> red
colors['rd'] = 'scarlet'
print colors['rd']
=> scarlet
 この場合、連想配列のすべてのキーの集まりが効果的なタクソノミー(taxonomy)となります。ここで重要なのは配列の中身ではなくキーの方だということに注意してください。なにより、配列の中身が何であろうと特に制約がない(他の配列であってもよい)からです。

連想配列

 伝統的なHTMLページを見てみると、<select>要素は通常、連想配列の使用を前提として機能しています。

colors = {rd : 'red', or : 'orange', ye : 'yellow', 
          gn : 'green', bu : 'blue', vi : 'violet'}
<select value="rd" name="colorkey">
  <option value="rd">red</option>
  <option value="or">orange</option>
  <option value="ye">yellow</option>
  <option value="gn">green</option>
  <option value="bu">blue</option>
  <option value="vi">violet</option>
</select>
 各オプションのテキストブロックには「ラベル」(配列の各アイテムの右側の部分)が含まれ、value属性には各アイテムの「名前」が指定されます。大事なのは、選択コントロールでアイテムが選択されてそのアイテムの「ラベル」がドロップダウンリストに表示されているときは、それに対応する「名前」(つまり各オプションのvalue属性値)がコントロールの値になることです。同様の式はXFormsでも使用できますが、次のように関連付けがもう少し明確に定義されます。

<xf:select1 ref="colorkey">
    <xf:item>
        <xf:label>red</xf:label>
        <xf:value>rd</xf:value>
    </xf:item>
 こうした概念は当然ほとんどのコンピュータ言語にとって基本的なものですが、次のように若干異なるモデルをXFormsで実現しようとした場合は、話が少々複雑になります。

<xf:model id="datamodel">
  <xf:instance id="data">
    <data>
      <colorkey>rd</colorkey>
    </data>
  </xf:instance>
  <xf:instance id="colors">
    <colors>
      <color name="rd" label="red"/>
      <color name="or" label="orange"/>
      <color name="ye" label="yellow"/>
      <color name="gn" label="green"/>
      <color name="bu" label="blue"/>
      <color name="vi" label="violet"/>
    </colors>
  </xf:instance>
</xf:model>
<xf:select1 ref="colorkey">
  <xf:itemset nodeset="instance('colors')//color">
    <xf:label ref="@label"/>
    <xf:value ref="@name"/>
  </xf:item>
</xf:select1>
 この場合、連想配列(ここではcolor要素の名前とラベルとして定義されています)は、選択コントロールから独立したdataインスタンスに含まれています。この場所は、HTMLを使ってきた人にとっては少し変に感じられます。HTMLでは、配列はコントロールの中にあります。しかし、XFormsのコンテンツを扱う場合にはこれが普通です。XFormsのコンテンツでは、コントロールは既存のデータ構造にビューだけを提供するという前提を基礎にしています。この連想配列は、特定のデータプロパティに対してどのような値が有効かを決定するための制約を定義するスキーマによく似た働きをします。

 ここまではよいでしょう。列挙されたリストを使ったスキーマは、スキーマ(特にXSDスキーマ)の使用法としてはごく一般的です。ではさらに進んで、制約リストを外部XMLファイルに移し、そこから取得するという方法を考えてみましょう。

<xf:model id="datamodel">
  <xf:instance id="data">
    <data>
      <colorkey>rd</colorkey>
    </data>
  </xf:instance>
  <xf:instance id="colors" src="colors.xml"/>
</xf:model>
<xf:select1 ref="colorkey">
  <xf:itemset nodeset="instance('colors')//color">
    <xf:label ref="@label"/>
    <xf:value ref="@name"/>
  </xf:item>
</xf:select1>
 概念的には、このアプローチはそれほど飛躍ではありません。ただし、もっと広い視野で何が起きているのか注意してみてください。色のリストがスキーマの一部であると見るならば、単にそのスキーマが分散したというだけの話です(少なくともスキーマの一部が、残りのスキーマの範囲外に存在しています)。繰り返しますが、このアプローチはそれほど変わったものではありません。ほとんどのスキーマでは何らかのモジュール化が行われているのが普通であり、モジュール化によってスキーマが分解され、いくつかの場所に分散されます。これでスキーマをネットワーク上で利用できるようになりますが、まだ制約があり静的です。

 では、もう一歩進んでみましょう。

<xf:model id="datamodel">
  <xf:instance id="data">
    <data>
      <colorkey>rd</colorkey>
    </data>
  </xf:instance>
  <xf:instance id="colors" src="''colors.xq''"/>
</xf:model>
<xf:select1 ref="colorkey">
  <xf:itemset nodeset="instance('colors')//color">
    <xf:label ref="@label"/>
    <xf:value ref="@name"/>
  </xf:item>
</xf:select1>
 この例では、ソースをXMLドキュメントから、REST呼び出しのXQueryの結果に変更しています(これを別のサーバー言語に置き換えても考え方は同じです)。また、それにともなって重大な変化が起きています。このクエリは、ある動的なプロセスが直前に発生することを前提としています。すなわち、このモデルが持つことのできる列挙はもはや静的ではないということです。たとえば、colors.xqがクレオラ製の(何億兆もの色数が入っている)クレヨン箱の中から、ランダムに12色のセットを取り出すとします。さらに、1日くらいで最初のセットの約5パーセントの色がなくなり、同じ分だけ追加されるとします。要するに、色セットの列挙リストを用意することはできても、その色セットの静的な定義はないという状況です。これは、XSDではモデル化できません。

 例が不自然に思えるかもしれませんが、これは前述したNordstromの店舗の問題とまったく同じであり、実際にWebアプリケーションの構築でよく見られるようになっている問題です。では、ただの空白テキストフィールドと制約のないセットにするべきなのかというと、そうではありません。このようなセットは未知のものではなく、いつでも検証可能ですが、動的な性質も備えているということです。このような検証は時間によって結果が変わってきます。その色は使えるかどうか、その店舗は営業中かどうか(閉まっていないか)という検証を行うには、時間をパラメータとして考慮しなければなりません。実世界の物事はこのように動いており、この事実を便宜上の都合で無視すると、結局はうまく機能しないモデル(およびアプリケーション)ができてしまいます。

読み取り専用Webサービスのシナリオ

 このようなパラメータ化ならうんざりするぐらいお馴染みだと思うならば、それは、Webサービスを使っているときに実際に同じ問題が起きているということです。とりあえず、HTTP GETプロトコルに基づいた読み取り専用Webサービスだけを考えてみましょう。読み取り専用Webサービスが使われそうな2つの異なるシナリオを取り上げます。

 1つ目のシチュエーションは、何らかの理由で問題のモデルをクライアント環境内に直接簡単に収めることができない場合です(データベースにホストされているとか、セキュリティの権限が絡んでいるなど)。こうしたサービスを「便宜的なサービス」と呼ぶことにします。理論的には情報をローカルにホストすることもできますが、そうするのは効率的ではありません。このケースでは、データ環境は基本的に静的です。同じ呼び出しを異なる時期に2回実行した場合、時間以外のパラメータが同じなら、2つの呼び出しは同じコンテンツを返します。このような呼び出しのスキーマを作成することは理論的に可能で、このスキーマには特定の値のセットが含まれることになります(大きくなる可能性はあります)。このアプローチの良い例が、郵便番号を地域の特定の区域にマッピングする郵便番号簿でしょう。郵便番号簿は変更される可能性がありますが、モデル作成者が気にしなければならないほど頻繁に変更されるものではありません。

 しかし、もう1つのシチュエーションはかなり興味深いものです。このケースはサービス自体が動的な環境を扱っています。たとえば、典型的なWebサービスとして、1日の始まりから現在の時間までの普通株の変動(+/?で差分を通知するようなもの)を取得するものを取り上げてみましょう。ポイントだけ説明すると、このサービスは、前回通知した期間以降に値が増加した特定の株のセットを一覧で表示します。この場合のタクソノミーは機能的かつ動的です。これをラジオボタンのリストとして実装し、個々の株をラジオボタンで表すならば、Webサービスをリフレッシュするたびにボタンの数やボタンのコンテンツが変化することになるでしょう。

 これはXFormsに限ったことではありません。実際、AJAX(Asynchronous JavaScript and XML)全般に見られるもっとたちの悪い問題の1つは、データモデルが拡散して分散するほど、データモデルのインスタンスを検証するのがますます難しくなるということです。そのため、オブジェクト指向プログラミングでもXMLでも、これまで考案されてきた検証の概念の大部分は役に立ちません。

 さて、ここで重大な疑問が出てきます。果たして検証は必要なのでしょうか? たとえ完全に信頼できるネットワークでも、「何らかの形態の検証は必要」という答えになるでしょう。そのようなネットワークでも、どこかの時点でXML(または関連するシリアライズされたコンテンツ)を作成する必要があり、そのXMLの作成プロセスに欠陥がある可能性があります。しかし、それにまつわる検証はむしろ包括的なユニットテストに組み込まれています。箱に封をし、この閉じたシステム内のコンテンツは有効で一貫性があると確定した後では、エラーの原因となるものはモデル自体の欠陥から来るものとしか考えられず、それは当然ながら検証では解決できません(そのような検証はモデルの一部です)。

 しかし、XMLコンテンツが環境の外側から入ってくる可能性を作った時点で、検証は困難になります。また、XMLの主な役割が異種のシステム間でメッセージをやり取りするフォーマットであるため、システムに入ってくるコンテンツが内部的に一貫性がありかつ正当なものであることを判断する何らかの方法が必要になるでしょう。

 しかし、静的なスキーマ言語は、せいぜい構造型または基本型の検証を提供できるに過ぎません。それでさえ、モデルが複雑になるに従って、そうしたスキーマが適切にコンテンツを検証できる可能性は運次第なものになります。モデルの外側に存在するタクソノミー情報は、とりわけ動的なコンテキストでは、検証することができません。さらに、メッセージの正当性は検証できません。

 1つ考えられるソリューションは、SOAP/WSDLの相互交換に特化した複雑なWebサービスのインフラストラクチャをセットアップし、識別管理のための連携システムを確立し、すべてを暗号化されたまとまりとして扱い、関係するすべてのシステムにまたがるハンドシェークメカニズムを本格的に構築して、インターネットという基本的に信頼できないネットワークを、閉じたプライベートな完全に信頼できるネットワークに変えることです。このアプローチは、ほとんどのWS-*イニシアチブの作成に大いに役立ちます。

見かけより単純なSchematron

 安全性には劣りますが、もっとシンプルなシステムにする方法もあります。それは、検証メカニズムに、スキーマファイルの外部のリソースと対話するだけのインテリジェンスを組み込むことです。実は、このアプローチはISO Schematronが採用しているものです。Schematronの背後にある考え方は見かけより単純です。Schematronドキュメントは、XMLで書かれたルールのコレクションから成り、各ルールはXPath式で表される特定のコンテキストを操作します。各ルール内には、コンテキストに関する特定の条件をテストする一連のアサーション(それ自体がXPath式と述語から成ります)が含まれます。条件が真なら何も起こりませんが、偽であればSchematronは特定のテキストまたはXHTMLフォーマットでメッセージを返します。カスタムのパーサーを使うこともできますが、ほとんどの一般的なSchematronのプロセスは次のように実行されます。

  1. Schematronドキュメントを作成する。
  2. 特別なSchematronのXSLTを使ってSchematronを変換し、続いて別のXSLT(Schematronフィルタ)を生成する。
  3. Schematronフィルタで検証されるファイルを変換してレポートを作成する。
  4. ユーザーまたは別のプロセスにレポートを渡す。
 このSchematronのアプローチはXSLT 1.0および2.0のプロセッサで使用できます(ただし一般的には2.0のアプローチをお勧めします。単純に、言語の機能がはるかに洗練されているからです)。どちらのバージョンも、重要な関数であるXSLTのdocument()関数を公開しています(ただし、XPath 1.0自体の一部ではありません)。

 document()関数は引数を2つ受け取ります。1番目の引数はURL文字列またはURLのノードセットで(2.0ではシーケンスの場合もあり)、2番目の引数はドキュメントのコンテキストです(通常は現在のノードの参照を引数の値として受け取ります)。この関数の結果は、渡されたURLから得られる1つ以上のドキュメントです。注目すべきは、これらのURL自体がパラメトリックなGETベースのWebサービスである場合、それに基づいて外部のサービスからコンテンツを取得して、動的なタクソノミーからコンテンツを検証できるということです。

 たとえば、1つのパラメータ(colorkey)を受け取るWebサービスがあり、そこから次のような形式のXMLノードが返されるものとします。

<color name="rd" label="Red" status="200" 
 statusMessage="Color is valid."/>
 このキーに対応する色が見つかった場合は、次のようなノードが返されます。

<color name="rd" label="Carmine" status="500" 
 statusMessage="Color rd was found, but has been retired."/>
 見つからない場合は、次のようなノードが返されます。

<color name="rd" label="(unknown)" status="400" 
 statusMessage="Color 'rd' was not found."/>
 これを利用して、既存のリソースを読み込み、サーバーに問い合わせを行い、アサーションが偽だったときに適切なエラーメッセージを生成するSchematronを作成することができます。具体的には次のようになります。

<schema xmlns=http://purl.oclc.org/dsdl/schematron>
  <pattern id="confirmTaxonomies">
    <rule context="colorkey">
      <let name="$keyValue" value="."/>
      <let name="colorDoc" 
         value="document(concat('colors.xq?colorkey=',$keyValue),.)"/>
      <assert test="$colorDoc[@status=200]">
        <value-of select="$colorDoc[@statusMessage]"/>
      </assert>
    </rule>
  </pattern>
</schema>
 この場合、パターンにはcolorkey要素に一致する1つのルールが含まれています。このルールでは、処理をわかりやすくするために最初にいくつかの式を定義した後、受け取ったコードの@statusが200(HTTP 200の"success"コードに該当)かどうかを判定します。そうでない場合(つまり、Webサービスがエラーを返した場合)は、バリデータはメッセージの詳細を出力処理ストリームに出力します。

 XMLデータストリームを扱う人は、ここで紹介したSchematronのようなものを、分散コンテキストでも正常に動作する宣言スキーマとして使うアプローチをもっと詳細に研究しなければなりません。ネットワークでの接続がますます進む環境では、検証自体も「グローバル化」する必要があり、よりいっそう機能性を高め、新しい処理モデルに移行していく必要があります。もはや、XMLコンテンツを単一の静的なドキュメントで記述できた時代は過ぎ去ろうとしているのです。

著者紹介

Kurt Cagle(Kurt Cagle)
ライター、情報アーキテクト、XML News NetworkとMetaphorical Webのウェブマスター。カナダ、ブリティッシュコロンビア州のビクトリア在住。

過去コラム集
XMLデータの変更をSDOで簡単に追跡する
漸進方式でJavaコードの品質を大きく向上させる
PHP5の新機能「リフレクションAPI」とその使用法
AJAXアプリケーションで標準的なブラウザナビゲーションを再現する
Java RTSによる金融アプリケーションの作成
エンタープライズソフトウェア構成をもっとシンプルに
Presentation Modelパターンによる動的XAMLフォームの作成
DataGridViewのカスタム列タイプの作成
SQL Serverにおける日付/時刻計算のベストプラクティス
Mylyn 2.0による効率的なタスク管理
海外のインターネットコム アメリカ韓国ドイツトルコ
関連企業のサイト:ストックフォト イラスト ネットストリート ホテル予約サイト タウン情報 出張 事業継承 シミュレーション トランクルーム 優待映画チケット 田舎暮らしガイド オリジナルデザインTシャツ ニタコエ
Copyright 2008 Jupitermedia Corporation All Rights Reserved. http://www.internet.com/
space.gif space.gif