スキーマに続くスキーマがあると仮定します(チュートリアル ここ から):
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
},
"type": "object",
"properties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": {
"allOf": [
{ "$ref": "#/definitions/address" },
{ "properties":
{ "type": { "enum": [ "residential", "business" ] } },
"required": ["type"]
}
]
}
}
}
有効なインスタンスは次のとおりです。
{
"shipping_address": {
"street_address": "1600 Pennsylvania Avenue NW",
"city": "Washington",
"state": "DC",
"type": "business"
}
}
shipping_address
の追加フィールドが無効になることを確認する必要があります。この目的でadditionalProperties
が存在することを知っています。これは「false」に設定する必要があります。ただし、次のように"additionalProprties":false
を設定する場合:
"shipping_address": {
"allOf": [
{ "$ref": "#/definitions/address" },
{ "properties":
{ "type": { "enum": [ "residential", "business" ] } },
"required": ["type"]
}
],
"additionalProperties":false
}
検証エラーが表示されます(チェック ここ ):
[ {
"level" : "error",
"schema" : {
"loadingURI" : "#",
"pointer" : "/properties/shipping_address"
},
"instance" : {
"pointer" : "/shipping_address"
},
"domain" : "validation",
"keyword" : "additionalProperties",
"message" : "additional properties are not allowed",
"unwanted" : [ "city", "state", "street_address", "type" ]
} ]
質問は次のとおりです。shipping_address
部分のみのフィールドを制限するにはどうすればよいですか?前もって感謝します。
[v4検証仕様のドラフトの著者はこちら]
JSONスキーマで最も一般的な問題、つまり、ユーザーが期待するとおりに継承を実行できないという根本的な問題に遭遇しました。しかし、同時にそれはその中核機能の1つです。
あなたがするとき:
"allOf": [ { "schema1": "here" }, { "schema2": "here" } ]
schema1
とschema2
は、互いの知識noを持っています。それらは独自のコンテキストで評価されます。
多くの人が遭遇するシナリオでは、schema1
で定義されたプロパティがschema2
に認識されることを期待しています。しかし、これは事実ではありません。
この問題が、私がドラフトv5について次の2つの提案をした理由です。
shipping_address
のスキーマは次のようになります。
{
"merge": {
"source": { "$ref": "#/definitions/address" },
"with": {
"properties": {
"type": { "enum": [ "residential", "business" ] }
}
}
}
}
strictProperties
でtrue
をaddress
に定義します。
ちなみに、私はあなたが言及しているウェブサイトの著者でもあります。
次に、ドラフトv3に戻ります。ドラフトv3はextends
を定義し、その値はスキーマまたはスキーマの配列のいずれかでした。このキーワードの定義により、インスタンスは現在のスキーマおよびextends
で指定されたすべてのスキーマに対して有効でなければならないことを意味しました。基本的に、ドラフトv4のallOf
はドラフトv3のextends
です。
これを考慮してください(ドラフトv3):
{
"extends": { "type": "null" },
"type": "string"
}
そして今、それ:
{
"allOf": [ { "type": "string" }, { "type": "null" } ]
}
それらは同じです。それとも多分それ?
{
"anyOf": [ { "type": "string" }, { "type": "null" } ]
}
またはその?
{
"oneOf": [ { "type": "string" }, { "type": "null" } ]
}
全体として、これは、ドラフトv3のextends
が、人々が期待したことを実際に実行したことがないことを意味します。ドラフトv4では、*Of
キーワードが明確に定義されています。
しかし、あなたが抱えている問題は、最も一般的に遭遇する問題です。したがって、この誤解の原因を完全に解消する私の提案です!
additionalProperties
は、イミディエートスキーマのproperties
またはpatternProperties
によって考慮されないすべてのプロパティに適用されます。
これは、次の場合に意味します:
{
"allOf": [
{ "$ref": "#/definitions/address" },
{ "properties":
{ "type": { "enum": [ "residential", "business" ] } },
"required": ["type"]
}
],
"additionalProperties":false
}
ここでadditionalProperties
は、兄弟レベルのproperties
エントリがないため、allプロパティに適用されます。allOf
内のエントリはカウントされません。
できることの1つは、properties
定義を1レベル上に移動し、インポートするプロパティのスタブエントリを提供することです。
{
"allOf": [{"$ref": "#/definitions/address"}],
"properties": {
"type": {"enum": ["residential", "business"]},
"addressProp1": {},
"addressProp2": {},
...
},
"required": ["type"],
"additionalProperties":false
}
これは、additionalProperties
が必要なプロパティに適用されないことを意味します。
Yves-Mのソリューション のわずかに簡略化されたバージョンを次に示します。
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
}
},
"required": [
"street_address",
"city",
"state"
]
}
},
"type": "object",
"properties": {
"billing_address": {
"$ref": "#/definitions/address"
},
"shipping_address": {
"allOf": [
{
"$ref": "#/definitions/address"
}
],
"properties": {
"type": {
"enum": [
"residential",
"business"
]
},
"street_address": {},
"city": {},
"state": {}
},
"required": [
"type"
],
"additionalProperties": false
}
}
}
これにより、ベースaddress
スキーマの必須プロパティの検証が保持され、必要なtype
プロパティがshipping_address
に追加されます。
additionalProperties
が直接の兄弟レベルのプロパティのみを考慮することは残念です。たぶんこれには理由があります。しかし、これが継承されたプロパティを繰り返す必要がある理由です。
ここでは、空のオブジェクト構文を使用して、単純化された形式で継承されたプロパティを繰り返しています。つまり、これらの名前のプロパティは、含まれる値の種類に関係なく有効です。しかし、ベースallOf
スキーマで宣言された型制約(およびその他の制約)を強制するために、address
キーワードに依存できます。
そして、すべてがうまくいきます:
{
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
}
}
},
"type": "object",
"properties": {
"billing_address": {
"allOf": [
{ "$ref": "#/definitions/address" }
],
"properties": {
"street_address": {},
"city": {},
"state": {}
},
"additionalProperties": false
"required": ["street_address", "city", "state"]
},
"shipping_address": {
"allOf": [
{ "$ref": "#/definitions/address" },
{
"properties": {
"type": {
"enum": ["residential","business"]
}
}
}
],
"properties": {
"street_address": {},
"city": {},
"state": {},
"type": {}
},
"additionalProperties": false
"required": ["street_address","city","state","type"]
}
}
}
billing_address
およびshipping_address
のそれぞれは、独自の必須プロパティを指定する必要があります。
彼のプロパティを他のプロパティと組み合わせたい場合、定義には"additionalProperties": false
を含めないでください。