參考

條件式地應用子結構描述

dependentRequired

dependentRequired 關鍵字 有條件地要求,如果物件中存在給定的屬性,則必須存在某些屬性。例如,假設我們有一個代表客戶的結構描述。如果你有他們的信用卡號碼,你也會想確保你有帳單地址。如果你沒有他們的信用卡號碼,則不需要帳單地址。我們使用 dependentRequired 關鍵字來表示一個屬性對另一個屬性的這種依賴關係。dependentRequired 關鍵字的值是一個物件。物件中的每個條目都從屬性名稱 *p* 映射到字串陣列,列出如果存在 *p* 則必須有的屬性。

在以下範例中,每當提供 credit_card 屬性時,也必須存在 billing_address 屬性

結構描述
{ "type": "object",
"properties": { "name": { "type": "string" }, "credit_card": { "type": "number" }, "billing_address": { "type": "string" } },
"required": ["name"],
"dependentRequired": { "credit_card": ["billing_address"] }}
資料
{ "name": "John Doe", "credit_card": 5555555555555555, "billing_address": "555 Debtor's Lane"}
符合綱要

這個實例 有一個 credit_card,但它缺少 billing_address

資料
{ "name": "John Doe", "credit_card": 5555555555555555}
不符合綱要

這樣是可以的,因為我們沒有 credit_card,也沒有 billing_address

資料
{ "name": "John Doe"}
符合綱要

請注意,相依性不是雙向的。擁有帳單地址而沒有信用卡號碼是可以的。

資料
{ "name": "John Doe", "billing_address": "555 Debtor's Lane"}
符合綱要

要解決上面的最後一個問題(相依性不是雙向的),當然,您可以明確定義雙向相依性

結構描述
{ "type": "物件",
"properties": { "name": { "type": "字串" }, "credit_card": { "type":

此實例具有 credit_card,但缺少 billing_address

資料
{ "name": "John Doe", "credit_card": 5555555555555555}
不符合綱要

此實例具有 billing_address,但缺少 credit_card

資料
{ "name": "John Doe", "billing_address": "555 Debtor's Lane"}
不符合綱要
草稿特定資訊
在 Draft 2019-09 之前,dependentRequireddependentSchemas 是一個名為 dependencies 的關鍵字。如果相依性的值是一個陣列,它的行為會像 dependentRequired,如果相依性的值是一個 schema,它的行為會像 dependentSchema

dependentSchemas

當給定的屬性存在時,dependentSchemas 關鍵字會有條件地套用 子綱要。此綱要的套用方式與 allOf 套用綱要的方式相同。不會合併或擴展任何內容。兩個綱要會獨立套用。

例如,以下是另一種寫出上述內容的方式

結構描述
{ "type": "object", "properties": { "name": { "type": "string" }, "credit_card": { "type": "number" } }, "required": ["name"], "dependentSchemas": { "credit_card": { "properties": { "billing_address": { "type": "string" } }, "required": ["billing_address"] } }}
資料
{ "name": "John Doe", "credit_card": 5555555555555555, "billing_address": "555 Debtor's Lane"}
符合綱要

此實例具有 credit_card,但缺少 billing_address

資料
{ "name": "John Doe", "credit_card": 5555555555555555}
不符合綱要

此實例具有 billing_address,但缺少 credit_card。這會通過驗證,因為這裡 billing_address 看起來只是一個額外的屬性

資料
{ "name": "John Doe", "billing_address": "555 Debtor's Lane"}
符合綱要
草稿特定資訊
在 Draft 2019-09 之前,dependentRequireddependentSchemas 是一個名為 dependencies 的關鍵字。如果相依性的值是一個陣列,它的行為會像 dependentRequired,如果相依性的值是一個 schema,它的行為會像 dependentSchema

If-Then-Else

Draft 7 的新功能

ifthenelse 關鍵字允許根據另一個綱要的結果套用子綱要,很像您可能在傳統程式語言中看到的 if/then/else 結構。

如果 if 有效,then 也必須有效(且 else 會被忽略。)如果 if 無效,else 也必須有效(且 then 會被忽略)。

如果未定義 thenelseif 的行為會如同它們具有 true 的值。

如果 then 和/或 else 出現在沒有 if 的綱要中,則 thenelse 會被忽略。

我們可以將其放入真值表的形式中,顯示 ifthenelse 何時有效以及整個綱要的有效性結果的組合

ifthenelse整個綱要
TT不適用T
TF不適用F
F不適用TT
F不適用FF
不適用不適用不適用T

例如,假設您想要撰寫一個綱要來處理美國和加拿大的地址。這些國家/地區具有不同的郵遞區號格式,並且我們想要根據國家/地區選擇要驗證的格式。如果地址在美國,則 postal_code 欄位是一個「郵遞區號」:五個數字,後接一個可選的四位數字後綴。如果地址在加拿大,則 postal_code 欄位是一個六位數的字母數字字串,其中字母和數字交替出現。

結構描述
{ "type": "object", "properties": { "street_address": { "type": "string" }, "country": { "default": "United States of America", "enum": ["United States of America", "Canada"] } }, "if": { "properties": { "country": { "const": "United States of America" } } }, "then": { "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } } }, "else": { "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } } }}
資料
{ "street_address": "1600 Pennsylvania Avenue NW", "country": "United States of America", "postal_code": "20500"}
符合綱要
資料
{ "street_address": "1600 Pennsylvania Avenue NW", "postal_code": "20500"}
符合綱要
資料
{ "street_address": "24 Sussex Drive", "country": "Canada", "postal_code": "K1M 1M4"}
符合綱要
資料
{ "street_address": "24 Sussex Drive", "country": "Canada", "postal_code": "10000"}
不符合綱要
資料
{ "street_address": "1600 Pennsylvania Avenue NW", "postal_code": "K1M 1M4"}
不符合綱要

在這個範例中,「country」並非必要屬性。因為 if 結構描述也不要求「country」屬性,所以它會通過並套用「then」結構描述。因此,如果未定義「country」屬性,預設行為是將「postal_code」驗證為美國郵遞區號。「default」關鍵字沒有作用,但為了讓結構描述的讀者更容易辨識預設行為,最好還是包含進去。

可惜的是,上述方法無法擴展到兩個以上的國家。但是,您可以將多組 ifthen 包裹在 allOf 中,以建立可擴展的東西。在這個範例中,我們將使用美國和加拿大的郵遞區號,但也會加入荷蘭的郵遞區號,它是由 4 個數字接著兩個字母組成。將此擴展到世界上其餘的郵遞區號,留給讀者作為練習。

結構描述
{ "type": "object", "properties": { "street_address": { "type": "string" }, "country": { "default": "United States of America", "enum": ["United States of America", "Canada", "Netherlands"] } }, "allOf": [ { "if": { "properties": { "country": { "const": "United States of America" } } }, "then": { "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } } } }, { "if": { "properties": { "country": { "const": "Canada" } }, "required": ["country"] }, "then": { "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } } } }, { "if": { "properties": { "country": { "const": "Netherlands" } }, "required": ["country"] }, "then": { "properties": { "postal_code": { "pattern": "[0-9]{4} [A-Z]{2}" } } } } ]}
資料
{ "street_address": "1600 Pennsylvania Avenue NW", "country": "United States of America", "postal_code": "20500"}
符合綱要
資料
{ "street_address": "1600 Pennsylvania Avenue NW", "postal_code": "20500"}
符合綱要
資料
{ "street_address": "24 Sussex Drive", "country": "Canada", "postal_code": "K1M 1M4"}
符合綱要
資料
{ "street_address": "Adriaan Goekooplaan", "country": "Netherlands", "postal_code": "2517 JX"}
符合綱要
資料
{ "street_address": "24 Sussex Drive", "country": "Canada", "postal_code": "10000"}
不符合綱要
資料
{ "street_address": "1600 Pennsylvania Avenue NW", "postal_code": "K1M 1M4"}
不符合綱要

if 模式中,required 關鍵字是必要的,否則如果未定義「country」,它們都會適用。如果將「美利堅合眾國」的 if 模式中的 required 關鍵字省略,它實際上會成為未定義「country」時的預設值。

即使「country」是一個必填欄位,仍然建議在每個 if 模式中都包含 required 關鍵字。驗證結果會相同,因為 required 會失敗,但是不包含它可能會為錯誤結果增加雜訊,因為它會針對所有三個 then 模式驗證「postal_code」,導致不相關的錯誤。

蘊含關係

在 Draft 7 之前,您可以使用模式組合關鍵字和稱為「蘊含」的布林代數概念來表達「if-then」條件。「A -> B」(讀作:A 蘊含 B)表示如果 A 為真,則 B 也必須為真。它可以表示為 !A || B,這可以表示為 JSON Schema。

結構描述
{ "type": "object", "properties": { "restaurantType": { "enum": ["fast-food", "sit-down"] }, "total": { "type": "number" }, "tip": { "type": "number" } }, "anyOf": [ { "not": { "properties": { "restaurantType": { "const": "sit-down" } }, "required": ["restaurantType"] } }, { "required": ["tip"] } ]}
資料
{ "restaurantType": "sit-down", "total": 16.99, "tip": 3.4}
符合綱要
資料
{ "restaurantType": "sit-down", "total": 16.99}
不符合綱要
資料
{ "restaurantType": "fast-food", "total": 6.99}
符合綱要
資料
{ "total": 5.25 }
符合綱要

蘊含關係的變體可以用來表達與 if/then/else 關鍵字相同的東西。if/then 可以表示為 A -> Bif/else 可以表示為 !A -> B,而 if/then/else 可以表示為 A -> B AND !A -> C

由於此模式並不是很直觀,建議您將條件式放入 $defs 中,並使用描述性的名稱,然後透過 $ref 將其引用到您的 schema 中,例如:"allOf": [{ "$ref": "#/$defs/sit-down-restaurant-implies-tip-is-required" }]

需要協助嗎?

您覺得這些文件有幫助嗎?

幫助我們讓文件更完善!

在 JSON Schema 中,我們重視文件貢獻,如同重視其他類型的貢獻一樣!

仍然需要協助嗎?

學習 JSON Schema 通常令人感到困惑,但別擔心,我們在這裡提供協助!