japan.internet.comThe Internet & IT Network
RSS
  • ニュース
  • コラム
  • リサーチ
  • ヘッドライン
  • 特集
  • ブログ
  • プレスリリース
  • 専門チャンネル
  • イベント
  • ランキング
  • ニュースメール
2009年7月4日
文字サイズ文字サイズ小文字サイズ中文字サイズ大
デベロッパー2008年4月29日 10:00

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

海外海外internet.com発の記事
  • このエントリーを含むはてなブックマーク
  • この記事をクリップ!
  • Buzzurlにブックマーク
  • Yahoo!ブックマークに登録
  • newsing it!
  • この記事をokyuuへインポート

はじめに

 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のウェブマスター。カナダ、ブリティッシュコロンビア州のビクトリア在住。
関連テーマ
このエントリーを含むはてなブックマーク この記事をクリップ!
BuzzurlにブックマークBuzzurlにブックマーク Yahoo!ブックマークに登録
この記事をokyuuへインポート
最新トップニュース
データメーション
【データメーション】
中国が「Green Dam」フィルタ規制を撤回(7月1日)
Graphic Design Forum
【Graphic Design Forum】
Chris Dickman(6月25日)
プライバシー ジャパン・インターネットコム版
【プライバシー ジャパン・インターネットコム版】
グーグル・ストリートビューの問題について総務省の見解(6月23日)
エンジニアの独り言
【エンジニアの独り言】
システムを「使う」時代のエンジニアに求められるもの(6月2日)
最新ハイテク講座
最新ハイテク講座
電気は家庭でつくる時代へ!燃料電池「エネファーム」(7月3日)
アクセス解析で見るWebマーケティング
アクセス解析で見るWebマーケティング
決定力を探るアクセス解析(7月3日)
百式のネットビジネス研究
百式のネットビジネス研究
ファーストフードを高級っぽく盛り付けて紹介している「Fancy Fast Food」(7月3日)
週刊-サイト別アクセス状況データ
週刊-サイト別アクセス状況データ
ビデオリサーチインタラクティブ調査(月間インターネットオーディエンスデータ)(7月2日)
成約率、反応率を上げる Web 文章術
成約率、反応率を上げる Web 文章術
言葉がダイレクトにキャッシュを生む(7月2日)
不況時代の Web ビジネス最適化講座
不況時代の Web ビジネス最適化講座
アクセス解析エキスパートここだけの話、Web コンシェルジュの“勉強法”こっそり教えます(7月2日)
「Webからの脅威」―その傾向と最新対策
「Webからの脅威」―その傾向と最新対策
不正プログラムの分類(7月1日)
DevX
DevX
JavaScriptとDOMによる動的なWebページの作成(6月30日)
エンジニア転職ノウハウ開発室
エンジニア転職ノウハウ開発室
今のままで大丈夫?3匹の子ブタ的キャリア危険度診断(6月30日)
アイレップの SEM フロンティア
アイレップの SEM フロンティア
Web サイトは「無駄な穴のたくさん開いたじょうご」〜サイト成果向上の基本的な考え方(6月30日)
Copyright 2009 Japan Internet.com K.K. All Rights Reserved.http://www.internet.com/