このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

HTMLフォームで使うデータ型のJSONスキーマ

JSONスキーマで定義できるデータ型の分類をまた載せます。

  1. 基本スカラー型: integer, number, string, boolean, null
  2. リスト型: 項目がすべて同じ型である配列型、項目の個数は任意
  3. タプル型: 決まった個数の項目を持つ配列型
  4. タプル+リスト型: 決まった個数の項目と、それに続く同じ型の任意個の項目を持つ配列型
  5. 閉じたオブジェクト型: 決まった個数のプロパティを持つオブジェクト型
  6. 開いたオブジェクト型: 決まった個数のプロパティと、同じ型の任意個のプロパティを持つオブジェクト型
  7. ユニオン型: 複数の型のどれかを意味する型
  8. 列挙型: 有限個の定数リテラルのどれかを意味する型
  9. 全称型: 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)を書かなくても、実質的に非空文字列だけが入力されます。

同様に空な配列が入力となることもありません。例えば、「整数のリスト」と型を指定しても、空なリストになることはありません。入力データが全体として空オブジェクト {} になることはありますが、プロパティの値に空オブジェクトは現れません。

  1. 空な文字列は入力されない。
  2. 空なリストは入力されない。
  3. プロパティ値として空なオブジェクトは入力されない。

[追記]

スキーマ定義から入力用フォームを生成するときに頭の痛い問題は、ラベルの可読性や国際化なんだよね。

例えば、次の定義があるとします。

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:再帰的処理ができない。