はじめに
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)となります。ここで重要なのは配列の中身ではなくキーの方だということに注意してください。なにより、配列の中身が何であろうと特に制約がない(他の配列であってもよい)からです。