JSONスキーマで定義できるデータ型の分類をまた載せます。
- 基本スカラー型: integer, number, string, boolean, null
- リスト型: 項目がすべて同じ型である配列型、項目の個数は任意
- タプル型: 決まった個数の項目を持つ配列型
- タプル+リスト型: 決まった個数の項目と、それに続く同じ型の任意個の項目を持つ配列型
- 閉じたオブジェクト型: 決まった個数のプロパティを持つオブジェクト型
- 開いたオブジェクト型: 決まった個数のプロパティと、同じ型の任意個のプロパティを持つオブジェクト型
- ユニオン型: 複数の型のどれかを意味する型
- 列挙型: 有限個の定数リテラルのどれかを意味する型
- 全称型: any
HTMLフォームから入力として使うデータ型は次のものでしょう。[追記]マルチセットじゃなくてセットですね。[/追記]
型 | フォームコントロール |
---|---|
number | input type=text |
string | input type=text, textarea |
boolean | input type=radio |
列挙型 | input type=radio |
有限 |
input type=checkbox |
リスト型 | 項目の型で決まる |
タプル型 | 項目ごとに決まる |
オブジェクト型 | プロパティごとに決まる |
JSONデータ型に対して入力用のコントロールが一意的に決まるように調整をしてみます。
いくつかの注意点
integerはnumberに含めることにします。string型を、「テキストフィールドで入力すべきか? テキストエリアで入力すべきか?」は、型だけでは決定できません。singlelineというスキーマ属性を追加することにします。また、有限マルチセットはJSONスキーマの型としては存在しないので、配列型で代用します。有限マルチセット型の判定のために、uniqueというスキーマ属性も追加することにします。unique=true である配列は、同じ値の項目が二度以上出現できないという制約を持ち、事実上有限マルチセットとなります。
それぞれのフォームコントロールに対応する型のJSONスキーマのスキーマをCatyスキーマ構文で書いてみます(ややこしいぞ)。FormInputSchema型は総称的に「なんらかのフォームコントロールで入力する型」を表します。
それぞれの型に応じて、対応するフォームコントロールをCatyのテンプレートを使って生成したいのですが、今のところテンプレートの能力が不足*1なので、とりあえず分類だけしておきます。
数値型のJSONスキーマ
type NumberSchema = { "type" : "number", "minimum" : number?, "maximum" : number? };
1行の文字列型のJSONスキーマ
type SinglelineTextSchema = { "type" : "string", "singleline" : true, "minLength" : number?, "maxLength" : number? };
複数行かもしれない文字列型のJSONスキーマ
type TextSchema = { "type" : "string", "minLength" : number?, "maxLength" : number? };
真偽値型のJSONスキーマ
type BooleanSchema = { "type" : "boolean", };
列挙型のJSONスキーマ
type EnumSchema = { "enum" : [(number | string)*](minItems=2) };
有限マルチセット型のJSONスキーマ
type MultisetSchema = { "type" : "array", "unique" : true, "items" : {"enum": [(number | string)*](minItems=2) } };
リスト型のJSONスキーマ
type ListSchema = { "type" : "array", "items" : FormInputSchema, "minItems" : number?, "maxItems" : number? };
タプル型のJSONスキーマ
type TupleSchema = { "type" : "array", "items" : [FormInputSchema*], };
オブジェクト型のJSONスキーマ
type ObjectSchema = { "type" : "object", "properties" : { * : FormInputSchema? } };
フォーム特有の現象
フォームによる入力では、そのメカニズムから生じるいくつかの現象があります。
空な文字列(テキスト)はフォームから送られないので、サーバー側で空な文字列を受け取ることはありません。stringに長さの制限(minLength=1)を書かなくても、実質的に非空文字列だけが入力されます。
同様に空な配列が入力となることもありません。例えば、「整数のリスト」と型を指定しても、空なリストになることはありません。入力データが全体として空オブジェクト {} になることはありますが、プロパティの値に空オブジェクトは現れません。
- 空な文字列は入力されない。
- 空なリストは入力されない。
- プロパティ値として空なオブジェクトは入力されない。
[追記]
スキーマ定義から入力用フォームを生成するときに頭の痛い問題は、ラベルの可読性や国際化なんだよね。
例えば、次の定義があるとします。
type person = { "fn" : string, "email" : string, "url" : string?, };
この定義から、例えば次のようなHTMLフォームを生成するのは、原理的には難しくありません。(JavaScriptからの利用などを考えて、メタ情報を属性で埋め込んでいます。)
<form datatypeName="person" > <div datatype="object" > <label>fn:<input datatype="string" name="fn" type="text" ></label><br> <label>email:<input datatype="string" name="email" type="text" ></label><br> <label>url:<input datatype="string" optional="true" name="url" type="text" ></label><br> </div> </form>
しかし、プロパティ名をそのままラベルに使っているのでUI上は好ましくありません。日本語のラベルをスキーマ側に書こうとかすると、型定義とUIの定義が混じってしまい、鬱陶しい。いっそ、プロパティ名に日本語を使ってはどうか:
type 人物情報 = { "名前" : string, "メールアドレス" : string, "URL" : string?, };
これは悪くない方法ですが、型定義をhCardと互換にしようとか思うと採用できません。
型定義の情報とUIを作るために必要な情報はズレているので、どうやってもスッキリとは解決出来ない問題みたいです。
[/追記]
*1:再帰的処理ができない。