參考
條件式地應用子結構描述
dependentRequired
dependentRequired
關鍵字 有條件地要求,如果物件中存在給定的屬性,則必須存在某些屬性。例如,假設我們有一個代表客戶的結構描述。如果你有他們的信用卡號碼,你也會想確保你有帳單地址。如果你沒有他們的信用卡號碼,則不需要帳單地址。我們使用 dependentRequired
關鍵字來表示一個屬性對另一個屬性的這種依賴關係。dependentRequired
關鍵字的值是一個物件。物件中的每個條目都從屬性名稱 *p* 映射到字串陣列,列出如果存在 *p* 則必須有的屬性。
在以下範例中,每當提供 credit_card
屬性時,也必須存在 billing_address
屬性
"properties": { "name": { "type": "string" }, "credit_card": { "type": "number" }, "billing_address": { "type": "string" } },
"required": ["name"],
"dependentRequired": { "credit_card": ["billing_address"] }}
這個實例 有一個 credit_card
,但它缺少 billing_address
。
這樣是可以的,因為我們沒有 credit_card
,也沒有 billing_address
。
請注意,相依性不是雙向的。擁有帳單地址而沒有信用卡號碼是可以的。
要解決上面的最後一個問題(相依性不是雙向的),當然,您可以明確定義雙向相依性
"properties": { "name": { "type": "字串" }, "credit_card": { "type":
此實例具有 credit_card
,但缺少 billing_address
。
此實例具有 billing_address
,但缺少 credit_card
。
dependentRequired
和 dependentSchemas
是一個名為 dependencies
的關鍵字。如果相依性的值是一個陣列,它的行為會像 dependentRequired
,如果相依性的值是一個 schema,它的行為會像 dependentSchema
。dependentSchemas
當給定的屬性存在時,dependentSchemas
關鍵字會有條件地套用 子綱要。此綱要的套用方式與 allOf 套用綱要的方式相同。不會合併或擴展任何內容。兩個綱要會獨立套用。
例如,以下是另一種寫出上述內容的方式
此實例具有 credit_card
,但缺少 billing_address
此實例具有 billing_address
,但缺少 credit_card
。這會通過驗證,因為這裡 billing_address
看起來只是一個額外的屬性
dependentRequired
和 dependentSchemas
是一個名為 dependencies
的關鍵字。如果相依性的值是一個陣列,它的行為會像 dependentRequired
,如果相依性的值是一個 schema,它的行為會像 dependentSchema
。If-Then-Else
if
、then
和 else
關鍵字允許根據另一個綱要的結果套用子綱要,很像您可能在傳統程式語言中看到的 if
/then
/else
結構。
如果 if
有效,then
也必須有效(且 else
會被忽略。)如果 if
無效,else
也必須有效(且 then
會被忽略)。
如果未定義 then
或 else
,if
的行為會如同它們具有 true
的值。
如果 then
和/或 else
出現在沒有 if
的綱要中,則 then
和 else
會被忽略。
我們可以將其放入真值表的形式中,顯示 if
、then
和 else
何時有效以及整個綱要的有效性結果的組合
if | then | else | 整個綱要 |
---|---|---|---|
T | T | 不適用 | T |
T | F | 不適用 | F |
F | 不適用 | T | T |
F | 不適用 | F | F |
不適用 | 不適用 | 不適用 | T |
例如,假設您想要撰寫一個綱要來處理美國和加拿大的地址。這些國家/地區具有不同的郵遞區號格式,並且我們想要根據國家/地區選擇要驗證的格式。如果地址在美國,則 postal_code
欄位是一個「郵遞區號」:五個數字,後接一個可選的四位數字後綴。如果地址在加拿大,則 postal_code
欄位是一個六位數的字母數字字串,其中字母和數字交替出現。
在這個範例中,「country」並非必要屬性。因為 if
結構描述也不要求「country」屬性,所以它會通過並套用「then」結構描述。因此,如果未定義「country」屬性,預設行為是將「postal_code」驗證為美國郵遞區號。「default」關鍵字沒有作用,但為了讓結構描述的讀者更容易辨識預設行為,最好還是包含進去。
可惜的是,上述方法無法擴展到兩個以上的國家。但是,您可以將多組 if
和 then
包裹在 allOf
中,以建立可擴展的東西。在這個範例中,我們將使用美國和加拿大的郵遞區號,但也會加入荷蘭的郵遞區號,它是由 4 個數字接著兩個字母組成。將此擴展到世界上其餘的郵遞區號,留給讀者作為練習。
在 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。
蘊含關係的變體可以用來表達與 if
/then
/else
關鍵字相同的東西。if
/then
可以表示為 A -> B
,if
/else
可以表示為 !A -> B
,而 if
/then
/else
可以表示為 A -> B AND !A -> C
。
由於此模式並不是很直觀,建議您將條件式放入 $defs
中,並使用描述性的名稱,然後透過 $ref
將其引用到您的 schema 中,例如:"allOf": [{ "$ref": "#/$defs/sit-down-restaurant-implies-tip-is-required" }]
。