「すごく単純なJSONパス式」は、いろいろな目的に使う予定でいます。すぐに思いつく用途は、JSONデータの部分(構成要素)へのアクセスです。例えば、次のようなAPIが考えられます。
- JsonValue get(JsonValue data, String path); // エラー報告は適当に考える
- void put(JsonValue data, String path, JsonValue value);
それと、「JSONスキーマ、さらに別構文」で述べたスキーマ定義でも使います。この「さらに別構文」についてここで敷衍します。以下で述べるスキーマ構文を「パス形式スキーマ」と呼ぶことにします -- パス(正確にはパスパターン)ごとに型を指定するスタイルだからです。
パスをもっと単純化する
パス形式スキーマ記述で使うために、単純なパスをさらに制限します。
// 余分な空白は入れないとする Path ::= '$' | Name | Path '.' Name | Path '.' NonNegativeInteger
つまり、ブラケットは使わず、オブジェクトのフィールド名は名前に限定します。
この単純化は、スキーマ記述の観点からは特に意味はありません。パス式を、HTMLフォーム内のname属性値として使いたいという事情からの制限です。
ワイルドカード
スキーマ記述では、2種類のワイルドカードが必要になります。
- '*' -- 任意の名前にマッチする
- '#' -- 任意の非負整数値にマッチする
例えば、contact.* は、contact.tel, contact.fax, contact.mail などにマッチします。hobbies.# は、hobbies.0, hobbies.1, hobbies.2 などにマッチします。member.#.contact.* のような表現もあります -- このパターンにマッチする例はmember.0.contact.fax, member.2.contact.mail などがあります。
ワイルドカードを含むかもしれないパス式をパスパターンと呼ぶことにします。ワイルドカードを含むパスパターンは、複数のパスを総称的に表すことになります。
パス形式スキーマの書き方
// トークンの間に空白を入れてもよい スキーマ ::= パス制約 (';' パス制約)* パス制約 ::= 空 | パス ':' 型仕様
「JSONスキーマ、さらに別構文」では、JSONのフィールド名を意識してパスパターンを二重引用符で囲んでいたけど、うるさいので要らない気がしてきました。
次の例は、平面内の点のリストを表現するデータのスキーマです。
$ : array; // リスト $.# : object; // 点を表すオブジェクト $.#.x : integer; // x-座標値 $.#.y : integer; // y-座標値 $.#.color : string?, // 色の名前、名前の正当性はアプリケーションでチェック default="black"; $.#.state : // 見えているかどうか enum? ["hidden", "shown"], default="shown"; $.#.* : any ; // 拡張可能
型を表す名前(string, enum, any)の直後の疑問符「?」は、省略可能性を表します。オリジナルのJSONスキーマでは optional=true というスキーマ属性を使いますが、ここでは、正規表現風に表現します。
$.#.x というパスパターンを見れば、$.# がオブジェクトであること、$が配列であることは推測できるので、$.# と $ に関する記述は省略できます。コメントも省略してコンパクトに書けば:
$.#.x : integer; $.#.y : integer; $.#.color : string?, default="black"; $.#.state : enum? ["hidden", "shown"], default="shown"; $.#.* : any
セミコロンは終端記号ではなくて分離記号なので、最後のセミコロンは不要ですが、空制約を認めているので、セミコロンをいくら書いても構文エラーにはなりません。スキーマ属性は、カンマで区切って並べて書きます。スキーマ属性の構文/意味はオリジナルのJSONスキーマと同じです。しかし、次の属性は無意味になってしまうので使えません。
- optional -- 型名に「?」を付ける。
- additionalProperties -- ワイルドカード「*」を使う。
- enum -- 属性ではなくてenum型がある
- options -- 列挙値にラベルが付けられる
- extends -- 現状、継承は使えない