網際網路工程任務組 | A. Wright,編輯 |
網際網路草案 | |
預定狀態:資訊性 | H. Andrews,編輯 |
截止日期:2021 年 8 月 1 日 | |
B. Hutton,編輯 | |
G. Dennis | |
2020 年 1 月 28 日 |
JSON 綱要:描述 JSON 文件的一種媒體類型
draft-bhutton-json-schema-00
JSON 綱要定義了媒體類型「application/schema+json」,這是一種基於 JSON 的格式,用於描述 JSON 資料的結構。JSON 綱要聲明 JSON 文件必須具有的外觀、從中提取資訊的方式,以及如何與之互動。「application/schema-instance+json」媒體類型提供了與「application/schema+json」的額外功能豐富的整合,其超越了「application/json」文件所能提供的功能。
此草案的問題列表可以在這裡找到:<https://github.com/json-schema-org/json-schema-spec/issues>。
如需其他資訊,請參閱<https://json-schema.dev.org.tw/>。
若要提供意見回饋,請使用此問題追蹤器、首頁上列出的溝通方式,或電子郵件聯絡文件編輯者。
本網際網路草案的提交完全符合 BCP 78 和 BCP 79 的規定。
網際網路草案是網際網路工程任務組 (IETF) 的工作文件。請注意,其他團體也可能將工作文件作為網際網路草案發布。目前的網際網路草案清單位於 https://datatracker.ietf.org/drafts/current/。
網際網路草案是有效期限最多六個月的草案文件,並且隨時可能被其他文件更新、取代或廢棄。將網際網路草案用作參考資料,或將其引用為「進行中的工作」以外的其他用途是不適當的。
本網際網路草案將於 2021 年 8 月 1 日到期。
版權 (c) 2020 IETF Trust 和被識別為文件作者的人員。保留所有權利。
本文件受本文件發佈之日生效的 BCP 78 和 IETF Trust 與 IETF 文件相關的法律條款 (https://trustee.ietf.org/license-info) 的約束。請仔細審閱這些文件,因為它們描述您對本文件的權利和限制。從本文件中擷取的程式碼元件必須包含「信簡化的 BSD 授權」文字,如 Trust 法律條款的第 4.e 節所述,並且在不提供任何保固的情況下提供,如「信簡化的 BSD 授權」中所述。
JSON 綱要是一種 JSON 媒體類型,用於定義 JSON 資料的結構。JSON 綱要旨在定義 JSON 資料的驗證、文件、超連結導覽和互動控制。
本規範定義了 JSON 綱要的核心術語和機制,包括透過參考指向另一個 JSON 綱要、取消參照 JSON 綱要參考、指定正在使用的方言、指定方言的詞彙要求,以及定義預期的輸出。
其他規範定義了執行有關驗證、連結、註解、導覽和互動斷言的詞彙。
本文件中使用的關鍵字「必須 (MUST)」、「不得 (MUST NOT)」、「必要 (REQUIRED)」、「應當 (SHALL)」、「不應當 (SHALL NOT)」、「應該 (SHOULD)」、「不應該 (SHOULD NOT)」、「建議 (RECOMMENDED)」、「可以 (MAY)」和「可選 (OPTIONAL)」應按照 RFC 2119 中所述進行解釋。
本文件中使用的術語「JSON」、「JSON 文字」、「JSON 值」、「成員」、「元素」、「物件」、「陣列」、「數字」、「字串」、「布林值」、「true」、「false」和「null」應按照 RFC 8259 中的定義進行解釋。
本文件提議一種新的媒體類型「application/schema+json」,以識別用於描述 JSON 資料的 JSON 綱要。它還提議另一種可選媒體類型「application/schema-instance+json」,以提供額外的整合功能。JSON 綱要本身就是 JSON 文件。本規範以及相關規範定義了一些關鍵字,允許作者以多種方式描述 JSON 資料。
JSON 綱要使用關鍵字來斷言 JSON 實例的限制或使用其他資訊註解這些實例。其他關鍵字用於將斷言和註解套用到更複雜的 JSON 資料結構,或基於某種條件。
為了方便重複使用,關鍵字可以組織到詞彙中。詞彙包含關鍵字清單及其語法和語意。方言定義為一組詞彙及其在中繼綱要中識別的所需支援。
JSON 綱要可以透過定義其他詞彙來擴展,或透過在任何詞彙之外定義其他關鍵字來不那麼正式地擴展。無法識別的個別關鍵字只會收集它們的值作為註解,而當宣告正在使用哪些詞彙時,可以控制對於無法識別的詞彙的行為。
本文件定義了一個核心詞彙,任何實作都「必須 (MUST)」支援,並且無法停用。其關鍵字都以「$」字元作為前綴,以強調其必要性。此詞彙對於「application/schema+json」媒體類型的運作至關重要,並用於引導載入其他詞彙。
此外,本文件還定義了一個「建議 (RECOMMENDED)」的關鍵字詞彙,用於有條件地應用子綱要,以及將子綱要套用到物件和陣列的內容。要為非簡單的 JSON 實例編寫綱要,無論這些綱要是用於斷言驗證、註解還是兩者皆是,都必須使用此詞彙或非常類似的詞彙。雖然它不是所需核心詞彙的一部分,但為了達到最大的互通性,本文件包含了此額外詞彙,並強烈建議使用。
用於結構驗證或超媒體註解等目的的其他詞彙在其他文件中定義。這些其他文件各自定義一種方言,其中收集了為該文件用途編寫綱要所需的標準詞彙集。
JSON 文件是使用 application/json 媒體類型描述的資訊資源(一系列八位元)。
在 JSON 綱要中,術語「JSON 文件」、「JSON 文字」和「JSON 值」是可以互換的,因為它定義的資料模型。
JSON Schema 僅針對 JSON 文件定義。然而,任何可以解析成或根據 JSON Schema 資料模型處理的文件或記憶體結構,都可以根據 JSON Schema 來解讀,包括像 CBOR 這類的媒體類型。
應用 Schema 的 JSON 文件被稱為「實例」(instance)。
JSON Schema 是針對 "application/json" 或相容的文件定義,包括具有 "+json" 結構語法後綴的媒體類型。
其中,本規範定義了 "application/schema-instance+json" 媒體類型,該類型定義了 URI 中片段的處理方式。
JSON Schema 根據資料模型來解讀文件。根據此資料模型解讀的 JSON 值稱為「實例」。
一個實例具有六種基本類型之一,並且根據類型具有一系列可能的值
空白和格式化的考量,包括在資料模型中相等的數字的不同詞彙表示形式,因此不在 JSON Schema 的範圍內。希望處理詞彙表示形式差異的 JSON Schema 詞彙表,應該定義關鍵字,以精確解讀資料模型內的格式化字串,而不是依賴可用的原始 JSON 表示形式的 Unicode 字元。
由於物件不能有兩個具有相同鍵的屬性,因此對於嘗試在單一物件中定義兩個具有相同鍵的屬性的 JSON 文件,其行為是未定義的。
請注意,JSON Schema 詞彙表可以自由定義它們自己的擴展類型系統。這不應與此處定義的核心資料模型類型混淆。例如,「integer」是一個詞彙表定義為關鍵字值的合理類型,但資料模型不區分整數和其他數字。
如果兩個 JSON 實例的類型相同,並且根據資料模型具有相同的值,則稱它們是相等的。具體來說,這表示
此定義暗示陣列的長度必須相同,物件的成員數量必須相同,物件中的屬性是無序的,無法定義多個具有相同鍵的屬性,而且僅僅是格式上的差異(縮排、逗號的位置、尾隨零)是無關緊要的。
可以將 JSON Schema 用於 JSON Schema 資料模型的超集合,其中實例可能不在六種 JSON 資料類型中的任何一種之外。
在這種情況下,註解仍然適用;但大多數驗證關鍵字將不起作用,因為它們總是會通過或總是會失敗。
自訂詞彙表可以定義對核心資料模型超集合的支援。Schema 本身可能只能在此超集中表達;例如,使用 "const" 關鍵字。
JSON Schema 文件,或簡稱 Schema,是用於描述實例的 JSON 文件。Schema 本身可以被解釋為實例,但應該始終使用媒體類型 "application/schema+json",而不是 "application/schema-instance+json"。"application/schema+json" 媒體類型被定義為提供 "application/schema-instance+json" 所提供的片段識別符語法和語意的超集合。
JSON Schema 必須是物件或布林值。
應用於實例的物件屬性稱為關鍵字或 Schema 關鍵字。廣義而言,關鍵字分為五個類別
關鍵字可能屬於多個類別,儘管應用程式應該僅基於其子 Schema 的結果產生斷言結果。它們不應定義獨立於其子 Schema 的其他約束。
同一 Schema 物件內的屬性關鍵字稱為相鄰關鍵字。
擴展關鍵字,即在本文件及其配套文件之外定義的關鍵字,可以自由定義其他行為。
JSON Schema 可能包含非 Schema 關鍵字的屬性。未知的關鍵字應視為註解,其中關鍵字的值為註解的值。
空的 Schema 是沒有屬性,或只有未知屬性的 JSON Schema。
布林 Schema 值 "true" 和 "false" 是微不足道的 Schema,無論實例值為何,它們總是將自身產生為斷言結果。它們永遠不會產生註解結果。
這些布林 Schema 的存在是為了闡明 Schema 作者的意圖並促進 Schema 處理的最佳化。它們的行為與以下 Schema 物件相同(其中 "not" 是本文件中定義的子 Schema 應用詞彙表的一部分)。
雖然空的 Schema 物件是明確的,但 "false" Schema 有許多可能的等價物。使用布林值可確保人類讀者和實作都清楚其意圖。
Schema 詞彙表,或簡稱詞彙表,是一組關鍵字、它們的語法和它們的語意。詞彙表通常圍繞特定目的組織。JSON Schema 的不同用途,例如驗證、超媒體或使用者介面生成,將涉及不同的詞彙表集合。
詞彙表是 JSON Schema 中重用的主要單元,因為 Schema 作者可以指示處理 Schema 時需要或可選哪些詞彙表。由於詞彙表由 meta-schema 中的 URI 識別,因此通用實作可以載入擴展以支援先前未知的詞彙表。雖然可以在任何詞彙表之外支援關鍵字,但沒有類似的機制來指示個別關鍵字的使用。
本身描述 Schema 的 Schema 稱為 meta-schema。Meta-schema 用於驗證 JSON Schema 並指定它們正在使用的詞彙表。
通常,meta-schema 將指定一組詞彙表,並驗證符合這些詞彙表語法的 Schema。但是,meta-schema 和詞彙表是分開的,以便允許 meta-schema 比詞彙表的規範要求更嚴格或更寬鬆地驗證 Schema 的一致性。Meta-schema 也可能描述和驗證不屬於正式詞彙表的其他關鍵字。
JSON Schema 資源是由 標準 絕對 URI 識別的 Schema。
根 Schema 是包含相關整個 JSON 文件的 Schema。根 Schema 始終是 Schema 資源,其中 URI 的確定方式如 9.1.1 節中所述。
某些關鍵字本身使用 Schema,允許 JSON Schema 巢狀
{ "title": "root", "items": { "title": "array item" } }
在此範例文件中,標題為「array item」的 Schema 是子 Schema,而標題為「root」的 Schema 是根 Schema。
與根 Schema 一樣,子 Schema 也是物件或布林值。
如 8.2.1 節所述,JSON Schema 文件可以包含多個 JSON Schema 資源。在不加限定的情況下使用時,「根 Schema」一詞指的是文件的根 Schema。在某些情況下,會討論資源根 Schema。資源的根 Schema 是其頂層 Schema 物件,如果該資源要提取到獨立的 JSON Schema 文件中,它也將是文件根 Schema。
無論多個 Schema 資源是嵌入還是通過參考連結,它們都以相同的方式處理,並具有相同的可用行為。
根據 RFC 6839 的 3.1 節,針對任何 +json 媒體類型指定的片段識別符的語法和語意應與 "application/json" 的指定相同。(在本文發佈時,沒有為 "application/json" 定義片段識別語法。)
此外,"application/schema+json" 媒體類型支援兩種片段識別符結構:純名稱和 JSON 指標。"application/schema-instance+json" 媒體類型支援一種片段識別符結構:JSON 指標。
在 RFC 6901 中描述了將 JSON 指標作為 URI 片段識別符的使用方式。對於「application/schema+json」,它支援兩種片段識別符語法,符合 JSON 指標語法的片段識別符(包括空字串)必須被解釋為 JSON 指標片段識別符。
根據 W3C 的片段識別符最佳實踐,「application/schema+json」中的純名稱片段識別符保留給引用本地命名的 schema。所有不符合 JSON 指標語法的片段識別符都必須被解釋為純名稱片段識別符。
在「application/schema+json」文件中定義和引用純名稱片段識別符的規範,請參閱 「$anchor」關鍵字章節。
一個實例可以是任何有效的 JSON 值,如 JSON 所定義。JSON Schema 對類型沒有任何限制:JSON Schema 可以描述任何 JSON 值,包括例如 null。
JSON Schema 與程式語言無關,並支援資料模型中描述的完整值範圍。然而,請注意,某些語言和 JSON 解析器可能無法在記憶體中表示 JSON 可描述的完整值範圍。
某些程式語言和解析器對浮點數和整數使用不同的內部表示法。
為了保持一致性,整數 JSON 數值不應該以小數部分進行編碼。
關鍵字可以使用正規表示式來表示約束,或將實例值限制為正規表示式。這些正規表示式應根據 ECMA-262,第 21.2.1 節中描述的正規表示式方言有效。
正規表示式應該使用 "u" 標誌(或等效標誌)構建,以提供 Unicode 支援,或以提供 ECMA-262 定義的 Unicode 支援的方式進行處理。
此外,鑑於正規表示式結構支援的高度差異,schema 作者應將自己限制在以下正規表示式標記:
最後,實作不得將正規表示式視為錨定,無論是開頭還是結尾。這表示,例如,模式「es」與「expression」相符。
額外的 schema 關鍵字和 schema 詞彙可以由任何實體定義。除非有明確的協議,schema 作者不應期望那些沒有明確記錄支援的實作支援這些額外的關鍵字和詞彙。實作應該將它們不支援的關鍵字視為註釋,其中關鍵字的值是註釋的值。
實作可以提供註冊或載入它們不直接支援的詞彙處理程式的能力。註冊和實作此類處理程式的確切機制取決於實作。
JSON Schema 關鍵字分為幾個通用行為類別。斷言驗證實例是否滿足約束,產生布林結果。註釋附加應用程式可以隨意使用的資訊。應用程式將子 schema 應用於實例的部分,並組合它們的結果。
擴充關鍵字應保持在這些類別內,請記住,特別是註釋非常靈活。複雜的行為通常最好根據註釋資料委派給應用程式,而不是直接作為 schema 關鍵字實作。但是,擴充關鍵字可以為特殊目的定義其他行為。
針對 schema 評估實例涉及針對實例中適當位置處理 schema 中的所有關鍵字。通常,應用程式關鍵字會被處理,直到達到沒有應用程式(因此沒有子 schema)的 schema 物件。根據應用程式的規則,針對 schema 物件中的斷言和註釋關鍵字評估實例中的適當位置,並將它們的結果收集到父 schema 中。
一旦其所有子 schema 都被評估,就可以完成父 schema 物件的評估,儘管在某些情況下,由於斷言結果,評估可能會被短路。當正在收集註釋時,由於需要檢查所有子 schema 以進行註釋收集,包括那些無法進一步更改斷言結果的子 schema,因此某些斷言結果短路是不可能的。
雖然大多數 JSON Schema 關鍵字可以自行評估,或者最多只需要考慮同一 schema 物件中相鄰關鍵字的值或結果,但少數關鍵字具有更複雜的行為。
關鍵字的詞彙範圍由物件和陣列的巢狀 JSON 資料結構決定。最大的範圍是整個 schema 文件。最小的範圍是沒有子 schema 的單個 schema 物件。
關鍵字可以使用部分值定義,例如 URI 參考,必須根據另一個值解析,例如另一個 URI 參考或完整 URI,該值是透過 JSON 文件的詞彙結構找到的。「$id」、「$ref」和「$dynamicRef」核心關鍵字,以及「base」JSON Hyper-Schema 關鍵字,都是此類行為的範例。
請注意,某些關鍵字(例如「$schema」)適用於整個 schema 資源的詞彙範圍,因此必須僅出現在 schema 資源的根 schema 中。
其他關鍵字可能會考慮 schema 評估期間存在的動態範圍,通常與實例文件一起。最外層的動態範圍是處理開始的 schema 物件,即使它不是 schema 資源根。從這個根 schema 到任何特定關鍵字的路徑(包括可能已解析的任何「$ref」和「$dynamicRef」關鍵字)都被視為關鍵字的「驗證路徑」。
詞彙範圍和動態範圍會保持一致,直到遇到參考關鍵字。雖然遵循參考關鍵字會將處理從一個詞彙範圍移動到另一個詞彙範圍,但從動態範圍的角度來看,遵循參考與下降到作為值存在的子 schema 沒有任何不同。該參考遠側的關鍵字透過動態範圍解析資訊時,會將參考的起始側視為它們的動態父級,而不是檢查本地詞彙上封閉的父級。
動態範圍的概念主要用於「$dynamicRef」和「$dynamicAnchor」,應被視為進階功能,在定義額外的關鍵字時應謹慎使用。當報告錯誤和收集的註釋時,它也會出現,因為可能會使用不同的動態範圍重複訪問相同的詞彙範圍。在這種情況下,告知使用者產生錯誤或註釋的動態路徑非常重要。
關鍵字行為可以使用子 schema和/或相鄰關鍵字(同一 schema 物件中的關鍵字)及其子 schema 的註釋結果來定義。此類關鍵字不得導致循環依賴。關鍵字可能會根據同一個schema 物件中是否存在另一個關鍵字來修改其行為。
遺失的關鍵字不得產生錯誤的斷言結果,不得產生註釋結果,也不得導致任何其他 schema 作為其自身行為定義的一部分進行評估。但是,鑑於遺失的關鍵字不會貢獻註釋,缺少註釋結果可能會間接更改其他關鍵字的行為。
在某些情況下,關鍵字遺失的關鍵字斷言行為與特定值產生的行為相同,並且關鍵字定義應在已知的情況下註明此類值。但是,即使產生預設行為的值在存在時會產生註釋結果,預設行為仍然不得產生註釋。
由於註釋收集在計算和記憶體方面都會增加顯著的成本,因此實作可以選擇不使用此功能。以收集的註釋指定的關鍵字應在適當時描述合理的替代方法。本文檔中的「items」和「additionalProperties」關鍵字示範了這種方法。
請注意,當關鍵字不可能有此類替代方法時,不支援註釋集合的實作將無法支援包含它們的那些關鍵字或詞彙。
識別符設定 schema 的標準 URI,或影響 URI 在參考中的解析方式,或兩者兼而有之。本文檔中定義的核心詞彙定義了幾個識別關鍵字,最值得注意的是「$id」。
標準 schema URI 在處理實例時不得更改,但影響 URI 參考解析的關鍵字可能具有僅在執行時才能完全確定的行為。
雖然可以使用自訂識別符關鍵字,但詞彙設計人員應注意不要擾亂核心關鍵字的運作。例如,本規範中的「$dynamicAnchor」關鍵字將其 URI 解析效果限制在匹配的「$dynamicRef」關鍵字,而不干擾「$ref」的行為。
應用程式允許構建比單個 schema 物件可以實現的更複雜的 schema。針對schema 文件評估實例從將根 schema 應用於完整實例文件開始。從那裡,使用稱為應用程式的關鍵字來確定應用哪些額外的 schema。此類 schema 可以就地應用於目前位置,或應用於子位置。
要應用的 schema 可以是子 schema,包含關鍵字值的全部或一部分。或者,應用器可以參照同一份 schema 文件中其他地方的 schema,或是不同文件中的 schema。識別這些被參照 schema 的機制由該關鍵字定義。
應用器關鍵字也定義了如何修改和/或組合子 schema 或被參照 schema 的布林值斷言結果,以產生應用器的布林值結果。應用器可以對子 schema 的斷言結果應用任何布林邏輯運算,但**不得**引入自身新的斷言條件。
註解結果會連同實例位置和 schema 關鍵字的位置一起保留,以便應用程式可以決定如何解讀多個值。
如7.5 節所述,應用器關鍵字可以參照要應用的 schema,而不是將其作為子 schema 包含在應用器的值中。在這種情況下,被應用的 schema 被稱為參照 schema,而包含應用器關鍵字的 schema 則稱為引用 schema。
雖然根 schema 和子 schema 是基於 schema 在 schema 文件中位置的靜態概念,但參照和引用 schema 是動態的。在針對 schema 評估實例期間,不同的 schema 對可能會發現它們自己處於各種參照和引用關係中。
對於某些 by-reference 應用器,例如 "$ref",參照 schema 可以通過對 schema 文件的詞法範圍進行靜態分析來確定。其他應用器,例如 "$dynamicRef"(帶有 "$dynamicAnchor"),可能會使用動態作用域,因此只能在用實例評估 schema 的過程中解析。
JSON Schema 可用於斷言 JSON 文件上的約束,該約束會通過或失敗斷言。此方法可用於驗證是否符合約束,或記錄滿足這些約束所需的要求。
JSON Schema 實現會在針對 schema 斷言評估實例時產生單一的布林值結果。
實例只能失敗 schema 中存在的斷言。
大多數斷言僅約束特定基本類型中的值。當實例的類型不是關鍵字所針對的類型時,該實例被認為符合該斷言。
例如,來自配套驗證詞彙的 "maxLength" 關鍵字:僅會限制某些字串(太長的字串)無效。如果實例是數字、布林值、null、陣列或物件,則它對此斷言有效。
此行為允許關鍵字更容易地與可以是多種基本類型的實例一起使用。配套驗證詞彙還包含 "type" 關鍵字,該關鍵字可以獨立地將實例限制為一個或多個基本類型。這允許簡潔地表達使用案例,例如可能返回特定長度的字串或 null 值的函數。
{ "type": ["string", "null"], "maxLength": 255 }
如果 "maxLength" 也將實例類型限制為字串,那麼表達起來會更加繁瑣,因為如此編寫的範例實際上不會允許 null 值。除非另有明確規定,否則每個關鍵字都會單獨評估,因此如果 "maxLength" 將實例限制為字串,那麼在 "type" 中包含 "null" 將不會有任何實際效果。
當實例驗證通過包含註解的 schema 物件及其所有父 schema 物件時,JSON Schema 可以使用資訊註解實例。該資訊可以是簡單的值,也可以根據實例內容計算得出。
註解會附加到實例中的特定位置。由於許多子 schema 可以應用於任何單一位置,應用程式可能需要決定如何處理由不同 schema 物件中相同 schema 關鍵字附加到相同實例位置的不同註解值。
與斷言結果不同,註解資料可以採用多種形式,這些形式會提供給應用程式以供它們自行決定如何使用。預計 JSON Schema 實作不會代表應用程式使用收集到的資訊。
除非另有說明,否則註解關鍵字的值是該關鍵字的值。但是,其他行為也是有可能的。例如,JSON Hyper-Schema 的 "links" 關鍵字是一種複雜的註解,它會根據實例資料部分產生值。
雖然斷言可以進行「短路」評估,但收集註解需要檢查應用於實例位置的所有 schema,即使它們無法改變整體的斷言結果。唯一的例外是,已驗證失敗的 schema 物件的子 schema 可以跳過,因為不會為失敗的 schema 保留註解。
註解由明確定義註解收集行為的關鍵字收集。請注意,布林值 schema 無法產生註解,因為它們不使用關鍵字。
收集的註解**必須**包含以下資訊:
應用程式可以根據貢獻該值的 schema 位置,決定要使用多個註解值中的哪一個。這旨在允許彈性的使用方式。收集 schema 位置有助於這種使用方式。
例如,請考慮此 schema,它使用來自驗證規範的註解和斷言
請注意,為了清楚起見,某些行會換行。
{ "title": "Feature list", "type": "array", "prefixItems": [ { "title": "Feature A", "properties": { "enabled": { "$ref": "#/$defs/enabledToggle", "default": true } } }, { "title": "Feature B", "properties": { "enabled": { "description": "If set to null, Feature B inherits the enabled value from Feature A", "$ref": "#/$defs/enabledToggle" } } } ], "$defs": { "enabledToggle": { "title": "Enabled", "description": "Whether the feature is enabled (true), disabled (false), or under automatic control (null)", "type": ["boolean", "null"], "default": null } } }
在此範例中,功能 A 和功能 B 都使用了可重複使用的 "enabledToggle" schema。該 schema 使用 "title"、"description" 和 "default" 註解。因此,應用程式必須決定如何處理功能 A 的額外 "default" 值,以及功能 B 的額外 "description" 值。
應用程式開發人員和 schema 作者需要就使用方式達成共識。對於此範例,假設他們同意使用最明確的 "default" 值,並且任何額外的、更通用的 "default" 值都會被忽略。我們也假設他們同意使用所有 "description" 文字,從最通用的文字開始,到最明確的文字結束。這要求 schema 作者撰寫以這種方式組合時可行的描述。
應用程式可以使用 schema 位置路徑來確定哪些值是什麼。功能直接 "enabled" 屬性 schema 中的值更明確,而使用 "$ref" 參照的可重複使用 schema 下的值則更通用。schema 位置路徑會顯示每個值是否是通過跨越 "$ref" 找到的。
因此,功能 A 將使用 true 的預設值,而功能 B 將使用 null 的通用預設值。功能 A 將僅具有來自 "enabledToggle" schema 的通用描述,而功能 B 將使用該描述,並附加其本地定義的描述,說明如何解釋 null 值。
請注意,其他應用程式可能會採取其他合理的方法。例如,應用程式可能會認為存在兩個不同的 "default" 值是一個錯誤,無論它們的 schema 位置如何。
產生錯誤斷言結果的 schema 物件**不得**產生任何註解結果,無論是來自它們自己的關鍵字還是來自子 schema 中的關鍵字。
請注意,整體 schema 結果可能仍然包含從其他 schema 位置收集的註解。給定此 schema
{ "oneOf": [ { "title": "Integer Value", "type": "integer" }, { "title": "String Value", "type": "string" } ] }
對於實例 "This is a string",標題註解 "Integer Value" 會被丟棄,因為該 schema 物件中的類型斷言失敗。標題註解 "String Value" 會保留,因為實例通過了字串類型斷言。
除了可能定義它們自己的註解結果之外,應用器關鍵字還會聚合在其子 schema 或參照 schema 中收集的註解。
第四類關鍵字只是保留一個位置,以保存可重複使用的元件或 schema 作者感興趣且不適合重複使用的資料。這些關鍵字不會影響驗證或註解結果。它們在核心詞彙中的目的是確保某些位置可用於某些目的,並且不會被擴充關鍵字重新定義。
雖然這些關鍵字不會直接影響結果,但如9.4.2 節所述,未識別的擴充關鍵字為可重複使用 schema 保留位置,在某些情況下可能會與參照產生不良的互動。
雖然在此文件或相關文件中定義的詞彙都沒有定義可以針對和/或載入實例資料的關鍵字,但其他詞彙可能會希望這樣做。
可以定義關鍵字以使用 JSON 指標或相對 JSON 指標來檢查當前評估位置之外的實例部分。
允許使用相對 JSON 指標調整位置的關鍵字,如果需要預設值,**應該**預設為使用目前位置。
本節中宣告的關鍵字(所有關鍵字都以 "$" 開頭)構成了 JSON Schema 核心詞彙。這些關鍵字是處理任何 schema 或中繼 schema(包括跨多個文件的 schema)所必需的,或者是為了保留關鍵字以用於需要保證互通性的目的而存在的。
為了引導進一步詞彙的處理,必須始終將核心詞彙視為強制性的。使用 "$vocabulary" 關鍵字宣告所使用詞彙的中繼 schema 必須明確列出核心詞彙,該詞彙的值**必須**為 true,表示它是必要的。
對於此詞彙(且僅限於此詞彙)的 false 值行為是未定義的,當存在 "$vocabulary" 但未包含 Core 詞彙時的行為也是未定義的。然而,建議實作偵測這些情況並在發生時引發錯誤。宣告元模式選擇性地使用 Core 是沒有意義的。
不使用 "$vocabulary" 的元模式必須被視為需要 Core 詞彙,如同其 URI 的值為 true 一般。
Core 詞彙目前的 URI 為:<https://json-schema.dev.org.tw/draft/2020-12/vocab/core>。
對應的元模式目前的 URI 為:<https://json-schema.dev.org.tw/draft/2020-12/meta/core>。
雖然 "$" 前綴並未正式保留給 Core 詞彙,但建議擴展關鍵字(在詞彙或其他地方)以 "$" 以外的字元開頭,以避免未來可能發生的衝突。
使用元模式和詞彙這兩個概念來告知實作如何解釋綱要。每個綱要都有一個元模式,可以使用 "$schema" 關鍵字宣告。
元模式有兩個用途
元模式與詞彙是分開的,允許以不同的方式組合詞彙,並允許元模式作者施加額外的約束,例如禁止某些關鍵字,或執行異常嚴格的語法驗證,這可能在開發和測試週期中完成。每個詞彙通常會識別一個僅包含該詞彙關鍵字的元模式。
元模式的撰寫是 JSON 綱要的進階用法,因此元模式功能的設計強調靈活性而非簡單性。
"$schema" 關鍵字既用作 JSON 綱要方言識別符,也用作資源的識別符,該資源本身是一個 JSON 綱要,描述了為此特定方言編寫的有效綱要集。
此關鍵字的值必須是 URI(包含 scheme),且此 URI 必須是標準化的。目前的綱要必須根據此 URI 所識別的元模式進行有效性驗證。
如果此 URI 識別可檢索的資源,則該資源的媒體類型應為 "application/schema+json"。
"$schema" 關鍵字應在文件根綱要物件中使用,並且可以嵌入式綱要資源的根綱要物件中使用。它不得出現在非資源根綱要物件中。如果文件根綱要中不存在,則產生的行為是實作定義的。
此屬性的值在此文件和其他文件中以及由其他方定義。
"$vocabulary" 關鍵字在元模式中使用,以識別在該元模式描述的綱要中可用的詞彙。它也用於指示每個詞彙是必需的還是可選的,意思是說,為了成功處理綱要,實作必須理解必需的詞彙。這些資訊共同構成一種方言。任何實作理解的詞彙都必須以符合詞彙中包含的語義定義的方式進行處理。
此關鍵字的值必須是一個物件。物件中的屬性名稱必須是 URI(包含 scheme),且此 URI 必須是標準化的。每個作為屬性名稱出現的 URI 都會識別一組特定的關鍵字及其語義。
該 URI 可以是一個 URL,但可檢索資源的性質目前是未定義的,並保留供未來使用。詞彙作者可以使用詞彙規範的 URL,以人類可讀的媒體類型(例如 text/html 或 text/plain)作為詞彙 URI。[CREF1]詞彙文件可能會在即將發布的草案中添加。目前,識別關鍵字集被認為是足夠的,因為這與元模式驗證一起,是目前「詞彙」的工作方式。任何未來的詞彙文件格式都將被指定為 JSON 文件,因此在此期間使用 text/html 或其他非 JSON 格式不會產生任何未來歧義。
物件屬性的值必須是布林值。如果值為 true,則不識別該詞彙的實作必須拒絕處理任何使用 "$schema" 宣告此元模式的綱要。如果值為 false,則不識別該詞彙的實作應繼續處理此類綱要。如果實作理解該詞彙,則該值沒有影響。
根據 6.5,無法識別的關鍵字應被視為註釋。對於無法識別的詞彙定義的關鍵字,情況仍然如此。目前無法區分在詞彙中定義的無法識別的關鍵字和不屬於任何詞彙的關鍵字。
"$vocabulary" 關鍵字應在任何旨在用作元模式的綱要文件的根綱要中使用。它不得出現在子綱要中。
在未作為元模式處理的綱要文件中,必須忽略 "$vocabulary" 關鍵字。這允許根據其自身的元模式 M' 驗證元模式 M,而無需驗證器理解 M 所宣告的詞彙。
如果缺少 "$vocabulary",實作可以根據元模式確定行為,如果可以從參照綱要的 "$schema" 關鍵字的 URI 值中識別該元模式。這是在詞彙存在之前識別行為(例如 Hyper-Schema 用法)的方式。
如果綱要引用的元模式無法識別或遺失,則行為由實作定義。如果實作繼續處理綱要,則必須假設使用核心詞彙。如果實作是為特定目的而建構的,則應假設使用所有與該目的最相關的詞彙。
例如,作為驗證器的實作應假設使用本規範和配套驗證規範中的所有詞彙。
請注意,對 "$vocabulary" 的處理限制意味著,使用 "$ref" 或類似關鍵字參照其他元模式的元模式不會自動繼承其他元模式的詞彙宣告。所有此類宣告都必須在每個旨在用作元模式的綱要文件的根目錄中重複。這在範例元模式中展示。[CREF2]此要求允許實作在每個元模式的單個位置找到所有詞彙要求資訊。由於綱要的可擴展性意味著可以通過參考來組合更精細的元模式的潛在方式是無止境的,因此要求實作預料所有可能性並在參照的元模式中搜索詞彙將會過於繁重。
可能會在規範草案之間發布更新的詞彙和元模式 URI,以糾正錯誤。實作應考慮在此規範草案之後和下一個草案之前發布的 URI,以指示與此處列出的相同的語法和語義。
為了區分龐大生態系統中的綱要,綱要由 URI 識別,並且可以通過指定其 URI 來嵌入對其他綱要的參考。
幾個關鍵字可以接受相對 URI-參考,或用於構建相對 URI-參考的值。對於這些關鍵字,有必要建立基礎 URI 以便解析參考。
"$id" 關鍵字使用其 標準 URI 識別綱要資源。
請注意,此 URI 是一個識別符,而不一定是網路定位符。在網路可尋址 URL 的情況下,綱要不一定可以從其標準 URI 下載。
如果存在,此關鍵字的值必須是字串,並且必須表示有效的 URI-參考。此 URI-參考應標準化,並且必須解析為 絕對 URI(沒有片段)。因此,"$id" 不得包含非空片段,且不應包含空片段。
由於 application/schema+json 媒體類型環境中的空片段表示與沒有片段的基礎 URI 相同的資源,因此實作可以通過刪除片段來標準化以空片段結尾的 URI。然而,綱要作者不應依賴跨實作的此行為。[CREF3]這主要是因為較舊的元模式在其 $id(或之前的 id)中具有空片段。未來的草案可能會完全禁止 "$id" 中的空片段。
根據 RFC 3986 第 5.1.1 節 關於嵌入在內容中的基礎 URI,此 URI 也充當綱要資源內關鍵字中相對 URI 參考的基礎 URI。
子架構中若存在「$id」,表示該子架構構成單一架構文件中一個獨立的架構資源。此外,根據關於封裝實體的 RFC 3986 第 5.1.2 節,如果子架構中的「$id」是相對 URI 參照,則解析該參照的基礎 URI 為父架構資源的 URI。
如果沒有父架構物件明確使用「$id」將自身識別為資源,則基礎 URI 為整個文件的 URI,如前一節中給定的步驟所建立。
JSON Schema 文件的根架構應包含一個帶有絕對 URI(包含 scheme,但不包含片段)的「$id」關鍵字。
使用 JSON 指標片段需要了解架構的結構。在編寫旨在提供可重複使用架構的架構文件時,最好使用未綁定到任何特定結構位置的純名稱片段。這樣可以重新定位子架構,而無需更新 JSON 指標參照。
「$anchor」和「$dynamicAnchor」關鍵字用於指定此類片段。它們是識別符關鍵字,只能用於建立純名稱片段,而不是像「$id」那樣的絕對 URI。
附加結果片段的基礎 URI 是包含相關「$anchor」或「$dynamicAnchor」的架構資源的標準 URI。如前一節所述,這要么是相同或父架構物件中最接近的「$id」,要么是根據 RFC 3986 確定的文件的基礎 URI。
與 URI 的常規用法不同,「$dynamicAnchor」表示當與「$dynamicRef」關鍵字一起使用時,該片段是一個擴充點。這種底層、進階功能使擴展遞迴架構(例如元架構)更容易,而不會對該擴展施加任何特定語義。有關詳細信息,請參閱關於「$dynamicRef」的部分。
在大多數情況下,正常的片段行為既足夠又更直觀。因此,建議使用「$anchor」來建立純名稱片段,除非明顯需要「$dynamicAnchor」。
如果存在此關鍵字,則其值必須為字串,且必須以字母([A-Za-z])或底線("_")開頭,後跟任意數量的字母、數字([0-9])、連字號("-")、底線("_")和句點(".")。這與 XML NCName 產出的 US-ASCII 部分匹配。[CREF4]請注意,錨點字串不包含「#」字元,因為它不是 URI 參照。「$anchor」:「foo」在使用 URI 時會變成片段「#foo」。請參閱下面的完整示例。
在同一資源內,使用「$anchor」和/或「$dynamicAnchor」的任何組合多次指定相同的片段名稱的效果是未定義的。如果檢測到此類用法,實作方式可能會引發錯誤。
可以使用多個關鍵字來參照將應用於目前實例位置的架構。「$ref」和「$dynamicRef」是應用程式關鍵字,將參照的架構應用於實例。
由於「$ref」和「$dynamicRef」的值是 URI 參照,因此可以將架構外部化或跨多個檔案劃分架構,並提供透過自我參照來驗證遞迴結構的能力。
這些關鍵字產生的已解析 URI 不一定是網路定位器,而僅是一個識別符。如果架構是可透過網路定址的 URL,則該架構不必可從該位址下載,並且實作方式不應假定在遇到可透過網路定址的 URI 時應該執行網路操作。
「$ref」關鍵字是一個應用程式,用於參照靜態識別的架構。其結果是參照架構的結果。[CREF5]請注意,此處如何確定結果的定義表示,其他關鍵字可以與同一架構物件中的「$ref」一起出現。
「$ref」關鍵字的值必須是作為 URI 參照的字串。針對目前的 URI 基礎解析後,會產生要套用的架構的 URI。此解析可以在架構載入時安全地執行,因為評估實例的過程不會改變參照的解析方式。
「$dynamicRef」關鍵字是一個應用程式,可延遲完整解析,直到執行階段,屆時每次在評估實例時遇到它時都會進行解析。
「$dynamicRef」與「$dynamicAnchor」一起實作了一個協作擴充機制,該機制主要用於遞迴架構(參照自身的架構)。擴充點和執行階段確定的擴充目標均使用「$dynamicAnchor」定義,並且僅在以「$dynamicRef」參照時才展現執行階段動態行為。
「$dynamicRef」屬性的值必須是作為 URI 參照的字串。針對目前的 URI 基礎解析後,會產生用作執行階段解析起點的 URI。此初始解析可以在架構載入時安全地執行。
如果初始解析的起點 URI 包含由「$dynamicAnchor」關鍵字建立的片段,則必須將初始 URI 替換為動態範圍中最外層架構資源的 URI(包括片段),該範圍使用「$dynamicAnchor」定義了名稱相同的片段。
否則,其行為與「$ref」相同,且不需要執行階段解析。
有關使用這些關鍵字的完整範例,請參閱附錄C。[CREF6]2019 年之前的草案中的超架構元架構與本草案之間的差異顯著地展示了這些關鍵字的實用性。
「$defs」關鍵字為架構作者保留一個位置,以將可重複使用的 JSON Schema 行內嵌入到更通用的架構中。此關鍵字不會直接影響驗證結果。
此關鍵字的值必須是一個物件。此物件的每個成員值都必須是有效的 JSON Schema。
例如,以下是一個描述正整數陣列的架構,其中正整數約束是「$defs」中的子架構
{ "type": "array", "items": { "$ref": "#/$defs/positiveInteger" }, "$defs": { "positiveInteger": { "type": "integer", "exclusiveMinimum": 0 } } }
此關鍵字為架構作者保留一個位置,以供架構讀者或維護者註解。
此關鍵字的值必須為字串。實作方式不得向最終用戶呈現此字串。用於編輯架構的工具應支援顯示和編輯此關鍵字。此關鍵字的值可用於針對使用架構的開發人員的除錯或錯誤輸出。
架構詞彙表應允許在包含詞彙表關鍵字的任何物件內使用「$comment」。除非詞彙表明確禁止,否則實作方式可以假定允許使用「$comment」。詞彙表不得指定「$comment」的任何影響,超出本規範中描述的內容。
在應用程式/架構+json 之間轉換其他媒體類型或程式語言的工具可能會選擇將該媒體類型或程式語言的本機註解轉換為「$comment」值或從「$comment」值轉換。當同時存在本機註解和「$comment」屬性時,此類轉換的行為取決於實作方式。
實作方式可以在處理期間的任何時間點移除「$comment」值。特別是,這允許在部署架構的大小受到關注時縮短架構。
實作方式不得根據「$comment」屬性的存在、不存在或內容採取任何其他動作。特別是,「$comment」的值不得作為註解結果收集。
RFC3986 第 5.1 節定義了如何確定文件的預設基礎 URI。
作為參考,架構的初始基礎 URI 是找到它的 URI,無論是網路位置、本機檔案系統,還是任何其他可透過任何已知 scheme 的 URI 識別的情況。
如果架構文件沒有使用「$id」(嵌入在內容中)定義明確的基礎 URI,則基礎 URI 是根據RFC 3986 第 5 節確定的 URI。
如果沒有已知的來源,或者沒有已知來源的 URI scheme,則可以使用適合的實作方式特定預設 URI,如RFC 3986 第 5.1.4 節中所述。建議實作方式記錄它們假設的任何預設基礎 URI。
如果架構物件嵌入在另一種媒體類型的文件中,則初始基礎 URI 是根據該媒體類型的規則確定的。
除非下節中描述的「$id」關鍵字出現在根架構中,否則此基礎 URI 應被視為架構文件根架構資源的標準 URI。
使用 URI 來識別遠端架構並不一定表示會下載任何內容,相反,JSON Schema 實作方式應提前了解它們將使用的架構以及識別它們的 URI。
當架構被下載時,例如由通用使用者代理(在執行階段才知道要下載哪些架構)下載時,請參閱超媒體用法。
根據驗證器對架構的信任,實作方式應能夠將任意 URI 與任意架構關聯,和/或自動關聯架構的「$id」給定的 URI。此類 URI 和架構可以在處理實例之前提供給實作方式,或者可以在處理架構文件時在架構文件中注意到,產生如附錄A 中所示的關聯。
一個架構可能(且很可能)有多個 URI,但一個 URI 無法識別多個架構。當多個架構嘗試識別為相同的 URI 時,驗證器應引發錯誤狀況。
如果實作方式因另一個架構的「$schema」關鍵字識別而檢查某個架構時,則必須將其識別為元架構。這表示單一架構文件有時可能被視為常規架構,有時則被視為元架構。
在檢驗一個本身也是元綱要的綱要時,當實作開始將其作為一般綱要處理時,會根據這些規則進行處理。然而,當因為檢查其自身的 "$schema" 值而第二次載入時,則會將其視為元綱要。因此,同一個文件在一個會期中會以兩種方式處理。
為了特定於實作的目的,例如預先載入常用的元綱要並預先檢查其詞彙支援需求,實作可以允許將綱要明確地作為元綱要傳遞。元綱要作者不得期望此類功能在不同實作之間可以互通。
綱要可以通過任何給定的 URI 來識別,包括 JSON 指標或直接由 "$id" 給出的 URI。在所有情況下,取消對 "$ref" 參照的參照都涉及首先根據 RFC 3986 解析其值作為相對於當前基本 URI 的 URI 參照。
如果結果 URI 識別出當前文件中的綱要,或實作可用的另一個綱要文件中的綱要,則應自動使用該綱要。
例如,考慮以下綱要
{ "$id": "https://example.net/root.json", "items": { "type": "array", "items": { "$ref": "#item" } }, "$defs": { "single": { "$anchor": "item", "type": "object", "additionalProperties": { "$ref": "other.json" } } } }
當實作遇到 <#/$defs/single> 綱要時,它會將 "$anchor" 值解析為相對於當前基本 URI 的片段名稱,以形成 <https://example.net/root.json#item>。
當實作然後查看 <#/items> 綱要內部時,它會遇到 <#item> 參照,並將其解析為 <https://example.net/root.json#item>,它已在此同一文件中看到定義,因此可以自動使用。
當實作遇到對 "other.json" 的參照時,它會將其解析為 <https://example.net/other.json>,這並未在此文件中定義。如果實作以其他方式提供了具有該識別符的綱要,則也可以自動使用。[CREF7]當參照的綱要未知時,實作應該做什麼?在哪些情況下允許自動網路取消參照?同源策略?使用者可配置的選項?在 Hyper-Schema 描述不斷演進的 API 的情況下,預計新綱要將動態新增到系統中,因此對預先載入綱要文件提出絕對要求是不可行的。
由於 JSON 指標 URI 片段是基於綱要文件的結構構建的,因此嵌入式綱要資源及其子綱要可以使用相對於其自身規範 URI 或相對於包含資源的 URI 的 JSON 指標片段來識別。
從概念上講,一組連結的綱要資源無論每個資源是使用綱要參照連結的單獨文件,還是結構化為具有一個或多個嵌入為子綱要的綱要資源的單個文件,都應該具有相同的行為。
由於當嵌入式綱要移動到單獨的文件並參照時,相對於父綱要資源的 URI 的涉及 JSON 指標片段的 URI 不再有效,因此應用程式和綱要不應使用此類 URI 來識別嵌入式綱要資源或其中的位置。
考慮以下包含另一個嵌入其中的綱要資源的綱要文件
{ "$id": "https://example.com/foo", "items": { "$id": "https://example.com/bar", "additionalProperties": { } } }
URI "https://example.com/foo#/items/additionalProperties" 指向嵌入式資源中 "additionalProperties" 關鍵字的綱要。然而,該綱要的規範 URI 是 "https://example.com/bar#/additionalProperties"。
現在考慮以下兩個使用 "$ref" 的 URI 值連結的綱要資源
{ "$id": "https://example.com/foo", "items": { "$ref": "bar" } } { "$id": "https://example.com/bar", "additionalProperties": { } }
在這裡,我們看到 "additionalProperties" 子綱要的規範 URI 仍然有效,而以 "#/items/$ref" 開頭的非規範 URI 現在解析為無值。
另請注意,"https://example.com/foo#/items" 在這兩種安排中都有效,但解析為不同的值。此 URI 最終的作用類似於資源的檢索 URI。雖然有效,但檢查解析的值並使用 "$id"(如果該值是子綱要),或解析參照並使用參照目標的 "$id" 更為可取。
實作可以選擇不支援透過非規範 URI 尋址綱要。因此,建議綱要作者僅使用規範 URI,因為使用非規範 URI 可能會降低綱要的互通性。[CREF8]這是為了避免要求實作追蹤每個綱要的一整疊可能的基本 URI 和 JSON 指標片段,因為如果綱要資源重新組織,除了其中一個以外的所有 URI 都將是脆弱的。有人認為這很容易,因此沒有必要禁止它,而另一些人則認為它使綱要識別複雜化,應該禁止。歡迎就此主題提供意見。
附錄 A 中提供了更多此類非規範 URI 的範例,以及要使用的適當規範 URI。
複合綱要文件定義為 JSON 文件(有時稱為「捆綁」綱要),它將多個嵌入式 JSON 綱要資源捆綁到同一個文件中,以方便傳輸。
每個嵌入式綱要資源都必須視為個別的綱要資源,遵循標準的綱要載入和處理要求,包括確定詞彙支援。
建立複合綱要文件的捆綁流程定義為取得對外部綱要資源的參照(例如 "$ref"),並將參照的綱要資源嵌入到參照文件中。應該以這樣的方式進行捆綁,使基本文件和任何參照/嵌入文件中的所有 URI(用於參照)都不需要更改。
每個嵌入式 JSON 綱要資源都必須使用 "$id" 關鍵字以 URI 識別自身,並且應使用 "$schema" 關鍵字來識別它在綱要資源根目錄中使用的方言。建議 "$id" 的 URI 識別符值是絕對 URI。
當參照引用應用程式程式的綱要資源被捆綁時,建議將綱要資源定位為包含綱要根目錄處的 "$defs" 物件的值。現在嵌入的綱要資源的 "$defs" 鍵可以是捆綁綱要的 "$id" 或其他形式的應用程式定義的唯一識別符(例如 UUID)。此鍵並非旨在在 JSON 綱要中參照,但應用程式可以使用它來輔助捆綁流程。
綱要資源可以嵌入到 "$defs" 以外的位置,其中該位置定義為綱要值。
捆綁的綱要資源不得透過替換參照它的綱要物件,或透過將綱要資源包裝在其他應用程式關鍵字中來捆綁。
為了產生相同的輸出,包含綱要文件中對先前外部綱要資源的參照不得更改,並且現在使用嵌入式綱要資源的 "$id" 解析為綱要。此類相同的輸出包括驗證評估以及結果註釋或錯誤中使用的 URI 或路徑。
雖然捆綁流程通常是建立複合綱要文件的主要方法,但也有可能並且預期有些文件是手工建立的,可能沒有先前單獨存在的個別綱要資源。
當單個文件中存在多個綱要資源時,未定義應使用哪種方言處理的綱要資源必須使用與封閉資源相同的方言進行處理。
由於任何可以參照的綱要也可以嵌入,嵌入式綱要資源可以使用其封閉資源的 "$schema" 值指定不同的處理方言。
鑑於複合綱要文件可能具有識別為使用不同方言的嵌入式資源,因此不應透過將元綱要應用於複合綱要文件作為實例來驗證這些文件。建議提供替代的驗證流程以驗證綱要文件。每個綱要資源都應根據其相關的元綱要單獨驗證。[CREF9]如果您知道正在驗證的綱要是什麼,您可以使用 "$id" 來識別綱要是否為複合綱要文件,當 "$id" 未在文件的根目錄中使用時,它會識別嵌入式資源。
如果複合綱要文件中所有嵌入式資源都識別為使用相同的方言,或者其中省略了 "$schema" 並因此預設為封閉資源的方言,則可以透過應用適當的元綱要來驗證。
綱要不得針對實例陷入無限迴圈。例如,如果兩個綱要 "#alice" 和 "#bob" 都具有參照另一個綱要的 "allOf" 屬性,則幼稚的驗證器可能會陷入嘗試驗證實例的無限遞迴迴圈。綱要不應使用這種無限遞迴巢狀結構;行為未定義。
子綱要物件(或布林值)透過它們與已知應用程式關鍵字或與佔位關鍵字(例如 "$defs")的使用來識別,這些關鍵字將一個或多個子綱要作為值。這些關鍵字可以是 "$defs" 和本文檔中的標準應用程式程式,或來自已知詞彙的擴充關鍵字,或特定於實作的自訂關鍵字。
未知關鍵字的多層結構能夠引入巢狀子綱要,這些子綱要將受 "$id" 的處理規則約束。因此,無法可靠地實作在此類無法辨識的結構中的參照目標,並且導致的行為未定義。同樣,已知不屬於綱要的值的已知關鍵字下的參照目標會導致未定義的行為,以避免讓實作有偵測此類目標的需求。[CREF10]這些情況類似於透過 HTTP 獲取綱要,但收到 Content-Type 不是 application/schema+json 的回應。實作當然可以嘗試將其解釋為綱要,但原始伺服器沒有保證它實際上是任何此類綱要。因此,將其解釋為綱要會產生安全性含義,並可能產生不可預測的結果。
請注意,與 "$defs" 語法和語義相同的單層自訂關鍵字不允許任何介入的 "$id" 關鍵字,因此在嘗試將任何參考目標用作綱要的實作中會正常運作。但是,此行為是實作特定的,且不得為了互通性而依賴此行為。
JSON 已被 HTTP 伺服器廣泛採用於自動化 API 和機器人。本節描述當與支援媒體類型和 Web 連結 的協定一起使用時,如何以更 RESTful 的方式增強 JSON 文件處理。
建議由綱要描述的實例使用 連結資料協定 1.0 第 8.1 節 定義的連結關係 "describedby",提供下載 JSON 綱要的連結。
在 HTTP 中,可以使用 Link 標頭將此類連結附加到任何回應。此類標頭的一個範例是
Link: <https://example.com/my-hyper-schema>; rel="describedby"
當用於網路上的超媒體系統時,HTTP 通常是分配綱要的首選協定。如果行為不當的用戶端在不必要的情況下,頻繁地透過網路提取綱要,而其實可以長時間快取綱要,這可能會對伺服器維護人員造成問題。
HTTP 伺服器應在 JSON 綱要上設定長期快取標頭。HTTP 用戶端應觀察快取標頭,且在其新鮮期內不重新請求文件。分散式系統應使用共用快取和/或快取 Proxy。
用戶端應設定或預先加上特定於 JSON 綱要實作或軟體產品的 User-Agent 標頭。由於符號會按重要性遞減的順序列出,因此 JSON 綱要程式庫名稱/版本應先於更通用的 HTTP 程式庫名稱(如果有的話)。例如
User-Agent: product-name/5.4.1 so-cool-json-schema/1.0.2 curl/7.43.0
用戶端應能夠使用 "From" 標頭發出請求,以便伺服器操作員可以聯絡行為可能不當的指令碼的所有者。
本節定義應用程式關鍵字的詞彙,建議將其用作其他詞彙的基礎。
未使用 "$vocabulary" 的 Meta-綱要應被視為要求此詞彙,如同其 URI 以 true 值存在一樣。
此詞彙(稱為「應用程式詞彙」)的目前 URI 為:<https://json-schema.dev.org.tw/draft/2020-12/vocab/applicator>。
對應的 Meta-綱要的目前 URI 為:<https://json-schema.dev.org.tw/draft/2020-12/meta/applicator>。
可能會在規範草案之間發布更新的詞彙和元模式 URI,以糾正錯誤。實作應考慮在此規範草案之後和下一個草案之前發布的 URI,以指示與此處列出的相同的語法和語義。
綱要關鍵字通常獨立運作,不會影響彼此的結果。
為了方便綱要作者,此詞彙中的關鍵字有一些例外情況
這些關鍵字將子綱要應用於實例中與父綱要應用位置相同的位置。它們允許以各種方式合併或修改子綱要結果。
這些關鍵字的子綱要會完全獨立評估實例,因此一個子綱要的結果不得影響同級子綱要的結果。因此,子綱要可以按任何順序應用。
這些關鍵字對應於用於組合或修改子綱要的布林判斷結果的邏輯運算子。它們對註釋收集沒有直接影響,但它們使相同的註釋關鍵字能夠以不同的值應用於實例位置。註釋關鍵字定義了組合此類值的自身規則。
此關鍵字的值必須是非空陣列。陣列的每個項目都必須是有效的 JSON 綱要。
如果實例對此關鍵字的值定義的所有綱要都成功驗證,則實例會針對此關鍵字成功驗證。
此關鍵字的值必須是非空陣列。陣列的每個項目都必須是有效的 JSON 綱要。
如果實例對此關鍵字的值定義的至少一個綱要成功驗證,則實例會針對此關鍵字成功驗證。請注意,當收集註釋時,必須檢查所有子綱要,以便從每個成功驗證的子綱要收集註釋。
此關鍵字的值必須是非空陣列。陣列的每個項目都必須是有效的 JSON 綱要。
如果實例對此關鍵字的值定義的恰好一個綱要成功驗證,則實例會針對此關鍵字成功驗證。
此關鍵字的值必須是有效的 JSON 綱要。
如果實例未能成功驗證此關鍵字定義的綱要,則該實例對此關鍵字有效。
其中三個關鍵字共同運作,以根據另一個子綱要的結果實作子綱要有條件的應用。第四個是特定條件案例的捷徑。
"if"、"then" 和 "else" 不得在子綱要邊界之間相互影響。換句話說,"allOf" 的一個分支中的 "if" 不得對另一個分支中的 "then" 或 "else" 產生影響。
當 "if"、"then" 或 "else" 不存在時,沒有預設行為。特別是,它們不得被視為存在一個空綱要,當 "if" 不存在時,"then" 和 "else" 都必須完全忽略。
此關鍵字的值必須是有效的 JSON 綱要。
此關鍵字的子綱要的驗證結果對整體驗證結果沒有直接影響。相反地,它控制評估 "then" 或 "else" 關鍵字中的哪一個。
成功驗證此關鍵字的子綱要的實例,也必須對 "then" 關鍵字的子綱要值(如果存在)有效。
未能驗證此關鍵字的子綱要的實例,也必須對 "else" 關鍵字的子綱要值(如果存在)有效。
如果正在收集註釋,則會以通常的方式從此關鍵字的子綱要中收集它們,包括當關鍵字存在而沒有 "then" 或 "else" 時。
此關鍵字的值必須是有效的 JSON 綱要。
當 "if" 存在,且實例成功驗證其子綱要時,如果實例也成功驗證此關鍵字的子綱要,則對此關鍵字的驗證會成功。
當 "if" 不存在,或當實例未能驗證其子綱要時,此關鍵字無效。在這種情況下,實作不得為了驗證或註釋收集目的,對此關鍵字評估實例。
此關鍵字的值必須是有效的 JSON 綱要。
當 "if" 存在,且實例未能驗證其子綱要時,如果實例成功驗證此關鍵字的子綱要,則對此關鍵字的驗證會成功。
當 "if" 不存在,或當實例成功驗證其子綱要時,此關鍵字無效。在這種情況下,實作不得為了驗證或註釋收集目的,對此關鍵字評估實例。
此關鍵字指定如果實例是物件且包含特定屬性時,會評估的子綱要。
此關鍵字的值必須是物件。物件中的每個值都必須是有效的 JSON 綱要。
如果物件索引鍵是實例中的屬性,則整個實例必須驗證子綱要。其使用取決於屬性的存在。
省略此關鍵字的行為與空物件相同。
這些關鍵字中的每一個都定義將其子綱要應用於子實例的規則,特別是物件屬性和陣列項目,並合併它們的結果。
"prefixItems" 的值必須是有效 JSON 綱要的非空陣列。
如果實例的每個元素都對相同位置的綱要(如果有的話)成功驗證,則驗證會成功。此關鍵字不會限制陣列的長度。如果陣列長度大於此關鍵字的值,則此關鍵字僅驗證相符長度的前綴。
此關鍵字會產生一個註釋值,該值是此關鍵字套用子綱要的最大索引。如果子綱要已套用於實例的每個索引(例如 "items" 關鍵字產生的),則該值可能是一個布林值 true。此註釋會影響 "items" 和 "unevaluatedItems" 的行為。
省略此關鍵字的判斷行為與空陣列相同。
"items" 的值必須是有效的 JSON 綱要。
此關鍵字將其子綱要應用於相同綱要物件中大於 "prefixItems" 陣列長度的索引處的所有實例元素,如該 "prefixItems" 關鍵字的註釋結果所報告。如果不存在此類註釋結果,則 "items" 將其子綱要應用於所有實例陣列元素。[CREF11]請注意,沒有 "prefixItems" 的 "items" 的行為與先前草案中 "items" 的綱要形式相同。當 "prefixItems" 存在時,"items" 的行為與先前的 "additionalItems" 關鍵字相同。
如果將 "items" 子綱要應用於實例陣列中的任何位置,則會產生布林值 true 的註釋結果,表示已針對此關鍵字的子綱要評估所有剩餘的陣列元素。
省略此關鍵字的判斷行為與空綱要相同。
實作可以選擇以產生相同效果的其他方式實作或最佳化此關鍵字,例如直接檢查 "prefixItems" 陣列是否存在以及大小。不支援註釋收集的實作必須如此做。
此關鍵字的值必須是有效的 JSON 綱要。
如果陣列實例的至少一個元素對給定綱要有效,則該實例對 "contains" 有效。即使找到第一個相符項之後,也必須將子綱要應用於每個陣列元素,以便收集其他關鍵字使用的註釋。這是為了確保收集所有可能的註釋。
從邏輯上講,將值子綱要應用於陣列中每個項目的驗證結果必須與 "false" 進行 OR 運算,從而產生整體驗證結果。
此關鍵字會產生一個註釋值,該值是此關鍵字在應用其子綱要時成功驗證的索引的陣列,按遞增順序排列。如果子綱要在應用於實例的每個索引時都成功驗證,則該值可能是一個布林值 "true"。如果此關鍵字綱要套用的實例陣列為空,則必須存在該註釋。
"properties" 的值必須是物件。此物件的每個值都必須是有效的 JSON 綱要。
如果對於同時出現在實例中和此關鍵字值中的每個名稱,該名稱的子實例都成功驗證對應的綱要,則驗證會成功。
此關鍵字的註釋結果是此關鍵字比對到的實例屬性名稱集。
省略此關鍵字的判斷行為與空物件相同。
「patternProperties」的值必須是一個物件。此物件的每個屬性名稱都應該是有效的正規表示式,根據 ECMA-262 正規表示式方言。此物件的每個屬性值都必須是有效的 JSON Schema。
如果實例中每個符合此關鍵字值中任何屬性名稱所表示的正規表示式的名稱,其對應的子實例都成功地通過與該符合的正規表示式相對應的每個 schema 驗證,則驗證成功。
此關鍵字的註釋結果是此關鍵字比對到的實例屬性名稱集。
省略此關鍵字的判斷行為與空物件相同。
「additionalProperties」的值必須是有效的 JSON Schema。
此關鍵字的行為取決於相同 schema 物件中「properties」和「patternProperties」的存在和註解結果。「additionalProperties」的驗證僅適用於實例名稱的子值,這些實例名稱未出現在「properties」或「patternProperties」的註解結果中。
對於所有此類屬性,如果子實例通過「additionalProperties」schema 的驗證,則驗證成功。
此關鍵字的註解結果是由此關鍵字的子 schema 驗證的實例屬性名稱的集合。
省略此關鍵字的判斷行為與空綱要相同。
實作可以選擇以其他方式實作或最佳化此關鍵字,只要產生相同的效果即可,例如直接針對實例屬性集檢查「properties」中的名稱和「patternProperties」中的模式。不支援註解收集的實作必須這樣做。
「propertyNames」的值必須是有效的 JSON Schema。
如果實例是一個物件,則當實例中的每個屬性名稱都通過提供的 schema 驗證時,此關鍵字會驗證成功。請注意,schema 測試的屬性名稱永遠會是字串。
省略此關鍵字的行為與空的 schema 相同。
這些關鍵字的目的在於使 schema 作者能夠將子 schema 套用於陣列項目或物件屬性,這些項目或屬性尚未成功地針對任何相鄰關鍵字的任何動態範圍子 schema 進行評估。
這些實例項目或屬性可能未成功地針對一個或多個相鄰的關鍵字子 schema 進行評估,例如當「anyOf」分支中的斷言失敗時。此類失敗的評估不被認為有助於判斷該項目或屬性是否已評估。僅考慮成功的評估。
如果陣列中的項目或物件屬性被「成功評估」,則從邏輯上講,會認為在預期的物件或陣列的表示形式方面是有效的。例如,如果一個子 schema 表示一輛汽車,該汽車需要 2 到 4 個輪子,「wheels」的值為 6,則實例物件不會被「評估」為一輛汽車,「wheels」屬性會被視為「未評估(成功地作為已知事物)」,並且不會保留任何註解。
請回想一下,相鄰的關鍵字是位於相同 schema 物件內的關鍵字,並且動態範圍子 schema 包括參考目標以及詞彙子 schema。
這些關鍵字的行為取決於適用於正在驗證的實例位置的相鄰關鍵字的註解結果。
未使用 "$vocabulary" 的 Meta-綱要應被視為要求此詞彙,如同其 URI 以 true 值存在一樣。
此詞彙的目前 URI,稱為「未評估應用程式詞彙」,為:<https://json-schema.dev.org.tw/draft/2020-12/vocab/unevaluated>。
對應的元 schema 的目前 URI 為:<https://json-schema.dev.org.tw/draft/2020-12/meta/unevaluated>。
可能會在規範草案之間發布更新的詞彙和元模式 URI,以糾正錯誤。實作應考慮在此規範草案之後和下一個草案之前發布的 URI,以指示與此處列出的相同的語法和語義。
Schema 關鍵字通常獨立運作,不會影響彼此的結果。但是,此詞彙中的關鍵字是值得注意的例外
「unevaluatedItems」的值必須是有效的 JSON Schema。
此關鍵字的行為取決於適用於正在驗證的實例位置的相鄰關鍵字的註解結果。具體來說,是來自「prefixItems」、「items」和「contains」的註解,當這些關鍵字與「unevaluatedItems」關鍵字相鄰時,可能會出現這些註解。這三個註解以及「unevaluatedItems」也可能來自任何和所有相鄰的就地應用程式關鍵字。這包括但不限於本文件中定義的就地應用程式。
如果沒有相關的註解,則必須將「unevaluatedItems」子 schema 套用於陣列中的所有位置。如果從任何相關的註解中出現布林值 true,則必須忽略「unevaluatedItems」。否則,必須將子 schema 套用於任何大於「prefixItems」最大註解值且未出現在任何「contains」註解值中的索引。
這表示在評估此關鍵字之前,必須先評估「prefixItems」、「items」、「contains」和所有就地應用程式。擴充關鍵字的作者不得定義需要在評估此關鍵字之後進行評估的就地應用程式。
如果「unevaluatedItems」子 schema 套用於實例陣列中的任何位置,則會產生布林值 true 的註解結果,類似於「items」的行為。
省略此關鍵字的判斷行為與空綱要相同。
「unevaluatedProperties」的值必須是有效的 JSON Schema。
此關鍵字的行為取決於適用於正在驗證的實例位置的相鄰關鍵字的註解結果。具體來說,是來自「properties」、「patternProperties」和「additionalProperties」的註解,當這些關鍵字與「unevaluatedProperties」關鍵字相鄰時,可能會出現這些註解。這三個註解以及「unevaluatedProperties」也可能來自任何和所有相鄰的就地應用程式關鍵字。這包括但不限於本文件中定義的就地應用程式。
「unevaluatedProperties」的驗證僅適用於實例名稱的子值,這些實例名稱未出現在適用於正在驗證的實例位置的「properties」、「patternProperties」、「additionalProperties」或「unevaluatedProperties」註解結果中。
對於所有此類屬性,如果子實例通過「unevaluatedProperties」schema 的驗證,則驗證成功。
這表示在評估此關鍵字之前,必須先評估「properties」、「patternProperties」、「additionalProperties」和所有就地應用程式。擴充關鍵字的作者不得定義需要在評估此關鍵字之後進行評估的就地應用程式。
此關鍵字的註解結果是由此關鍵字的子 schema 驗證的實例屬性名稱的集合。
省略此關鍵字的判斷行為與空綱要相同。
JSON Schema 的定義是與平台無關的。因此,為了提高跨平台的相容性,實作應符合標準的驗證輸出格式。本節說明消費者需要正確解譯驗證結果的最低要求。
JSON Schema 輸出是使用第 4.2.1 節中描述的 JSON Schema 資料實例模型來定義的。實作可以根據其特定語言和平台所支援的方式偏離此模型,但是建議輸出可以透過序列化或其他方式轉換為本文中定義的 JSON 格式。
本規範定義了四種輸出格式。有關每種格式的要求,請參閱「輸出結構」部分。
實作應至少提供「旗標」、「基本」或「詳細」格式中的一種,並且可以提供「冗長」格式。如果提供一種或多種「詳細」或「冗長」格式,則還必須提供「旗標」格式。實作應在其文件中指定它們支援的格式。
除了簡單的「旗標」輸出之外,其他資訊對於協助偵錯 schema 或實例很有用。每個子結果都應至少包含本節中包含的資訊。
包含所有這些元件的單個物件被視為一個輸出單元。
實作可以選擇提供其他資訊。
驗證路徑之後的驗證關鍵字的相對位置。該值必須表示為 JSON 指標,並且必須包含任何按參考應用程式,例如「$ref」或「$dynamicRef」。
#/properties/width/$ref/minimum
請注意,由於包含這些按參考應用程式關鍵字,因此此指標可能無法通過正常的 JSON 指標流程解析。
此資訊的 JSON 金鑰是「keywordLocation」。
驗證關鍵字的絕對、已取消參考的位置。該值必須表示為使用相關 schema 物件的規範 URI 的完整 URI,並且不得包含按參考應用程式,例如「$ref」或「$dynamicRef」作為非終端路徑元件。如果錯誤或註解是針對該關鍵字,例如無法解析的參考,則可能會以這類關鍵字結尾。 [CREF12]請注意,此處的「絕對」是指「絕對檔案系統路徑」(表示完整位置)的意義,而不是 RFC 3986 中的「絕對 URI」術語(表示帶有 schema 但沒有片段)。關鍵字絕對位置將具有一個片段,以便識別關鍵字。
https://example.com/schemas/common#/$defs/count/minimum
只有在動態範圍沒有傳遞參考,或者 schema 沒有將絕對 URI 宣告為其「$id」時,才可以省略此資訊。
此資訊的 JSON 金鑰是「absoluteKeywordLocation」。
正在驗證的實例中 JSON 值的位置。該值必須表示為 JSON 指標。
此資訊的 JSON 金鑰是「instanceLocation」。
驗證產生的錯誤或註解。
對於錯誤,此規範未定義訊息的特定措辭。實作將需要提供此訊息。
對於註解,每個產生註解的關鍵字都會指定其格式。預設情況下,它是關鍵字的值。
失敗驗證的 JSON 金鑰是「error」;成功驗證的 JSON 金鑰是「annotation」。
對於這兩個階層式結構,此屬性將會包含巢狀的錯誤與註解。
在驗證失敗時,巢狀結果的 JSON 鍵為「errors」;對於驗證成功,則為「annotations」。請注意複數形式,因為具有巢狀結果的關鍵字也可能會有本機的錯誤或註解。
輸出必須是一個包含名為「valid」的布林屬性的物件。當需要關於結果的額外資訊時,輸出也必須包含如下所述的「errors」或「annotations」。
在這些範例中,將會使用以下綱要和實例。
{ "$id": "https://example.com/polygon", "$schema": "https://json-schema.dev.org.tw/draft/2020-12/schema", "$defs": { "point": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "additionalProperties": false, "required": [ "x", "y" ] } }, "type": "array", "items": { "$ref": "#/$defs/point" }, "minItems": 3 } [ { "x": 2.5, "y": 1.3 }, { "x": 1, "z": 6.7 } ]
這個實例將會驗證失敗並產生錯誤,但要推導出產生註解的通過綱要範例是很容易的。
具體而言,它將產生的錯誤為
請注意,這些範例中描述的錯誤訊息措辭並非本規範的要求。實作應製作適合其受眾的錯誤訊息,或提供允許使用者製作自己訊息的樣板機制。
在最簡單的情況下,只需要滿足「valid」屬性的布林結果。
{ "valid": false }
由於此格式不返回任何錯誤或註解,因此建議實作使用短路邏輯,以便在可以確定結果時立即返回失敗或成功。例如,如果「anyOf」關鍵字包含五個子綱要,而第二個通過,則無需檢查其他三個。邏輯可以直接返回成功。
「基本」結構是輸出單元的扁平列表。
{ "valid": false, "errors": [ { "keywordLocation": "", "instanceLocation": "", "error": "A subschema had errors." }, { "keywordLocation": "/items/$ref", "absoluteKeywordLocation": "https://example.com/polygon#/$defs/point", "instanceLocation": "/1", "error": "A subschema had errors." }, { "keywordLocation": "/items/$ref/required", "absoluteKeywordLocation": "https://example.com/polygon#/$defs/point/required", "instanceLocation": "/1", "error": "Required property 'y' not found." }, { "keywordLocation": "/items/$ref/additionalProperties", "absoluteKeywordLocation": "https://example.com/polygon#/$defs/point/additionalProperties", "instanceLocation": "/1/z", "error": "Additional property 'z' found but was invalid." }, { "keywordLocation": "/minItems", "instanceLocation": "", "error": "Expected at least 3 items but found 2" } ] }
「詳細」結構基於綱要,對於人類和機器來說都更具可讀性。以這種方式組織結構可以使錯誤之間的關聯更加明顯。例如,在「基本」結構中,遺失的「y」屬性和額外的「z」屬性都源自實例中的同一位置,這一點並不明顯。在階層中,這種關聯更容易識別。
以下規則控制結果物件的建構
分支節點不需要錯誤訊息或註解。
{ "valid": false, "keywordLocation": "", "instanceLocation": "", "errors": [ { "valid": false, "keywordLocation": "/items/$ref", "absoluteKeywordLocation": "https://example.com/polygon#/$defs/point", "instanceLocation": "/1", "errors": [ { "valid": false, "keywordLocation": "/items/$ref/required", "absoluteKeywordLocation": "https://example.com/polygon#/$defs/point/required", "instanceLocation": "/1", "error": "Required property 'y' not found." }, { "valid": false, "keywordLocation": "/items/$ref/additionalProperties", "absoluteKeywordLocation": "https://example.com/polygon#/$defs/point/additionalProperties", "instanceLocation": "/1/z", "error": "Additional property 'z' found but was invalid." } ] }, { "valid": false, "keywordLocation": "/minItems", "instanceLocation": "", "error": "Expected at least 3 items but found 2" } ] }
「詳盡」結構是一個完全實現的階層,與綱要的階層完全匹配。此結構適用於表單產生和驗證,其中錯誤的位置非常重要。
此結構與「詳細」結構的主要區別在於,會返回所有結果。這包括否則會被移除的子綱要驗證結果(例如,驗證失敗的註解、`not` 關鍵字內部的成功驗證等)。因此,建議每個節點也都攜帶一個 `valid` 屬性,以指示該節點的驗證結果。
由於此輸出結構可能非常大,因此在此處給出一個較小的範例以簡潔表示。上述範例的完整輸出結構 URI 為:<https://json-schema.dev.org.tw/draft/2020-12/output/verbose-example>。
// schema { "$id": "https://example.com/polygon", "$schema": "https://json-schema.dev.org.tw/draft/2020-12/schema", "type": "object", "properties": { "validProp": true, }, "additionalProperties": false } // instance { "validProp": 5, "disallowedProp": "value" } // result { "valid": false, "keywordLocation": "", "instanceLocation": "", "errors": [ { "valid": true, "keywordLocation": "/type", "instanceLocation": "" }, { "valid": true, "keywordLocation": "/properties", "instanceLocation": "" }, { "valid": false, "keywordLocation": "/additionalProperties", "instanceLocation": "", "errors": [ { "valid": false, "keywordLocation": "/additionalProperties", "instanceLocation": "/disallowedProp", "error": "Additional property 'disallowedProp' found but was invalid." } ] } ] }
為了方便起見,已提供 JSON Schema 來驗證實作產生的輸出。其 URI 為:<https://json-schema.dev.org.tw/draft/2020-12/output/schema>。
綱要和實例都是 JSON 值。因此,適用於 RFC 8259 中定義的所有安全性考量。
實例和綱要都經常由不受信任的第三方編寫,並部署在公共網際網路伺服器上。驗證器應注意,針對綱要的解析和驗證不會消耗過多的系統資源。驗證器絕不能陷入無限迴圈。
惡意方可能會導致實作重複收集一個非常大的值作為註解。在這種情況下,實作應防止過度消耗系統資源。
伺服器必須確保惡意方無法透過上傳具有現有或非常相似的「$id」的綱要來變更現有綱要的功能。
個別的 JSON Schema 詞彙表也可能會有自己的安全性考量。請參閱各自的規格以取得更多資訊。
綱要作者應注意「$comment」的內容,因為惡意實作可能會違反規範將其顯示給終端使用者,或者如果預期此行為則無法將其刪除。
惡意的綱要作者可能會在「$comment」中放置可執行程式碼或其他危險材料。實作絕不能根據「$comment」的內容來解析或採取其他動作。
JSON Schema 的建議 MIME 媒體類型定義如下
對於需要特定於 JSON Schema 的媒體類型的 JSON Schema 實例,建議的 MIME 媒體類型定義如下
[ecma262] | 「ECMA-262,第 11 版規格」,2020 年 6 月。 |
[RFC2119] | Bradner, S.,「在 RFC 中用於指示需求層級的關鍵字」,BCP 14,RFC 2119,DOI 10.17487/RFC2119,1997 年 3 月。 |
[RFC3986] | Berners-Lee, T.、Fielding, R. 和 L. Masinter,「統一資源識別符號 (URI):通用語法」,STD 66,RFC 3986,DOI 10.17487/RFC3986,2005 年 1 月。 |
[RFC6839] | Hansen, T. 和 A. Melnikov,「其他媒體類型結構化語法後綴」,RFC 6839,DOI 10.17487/RFC6839,2013 年 1 月。 |
[RFC6901] | Bryan, P.、Zyp, K. 和 M. Nottingham,「JavaScript 物件表示法 (JSON) 指標」,RFC 6901,DOI 10.17487/RFC6901,2013 年 4 月。 |
[RFC8259] | Bray, T.,「JavaScript 物件表示法 (JSON) 資料交換格式」,STD 90,RFC 8259,DOI 10.17487/RFC8259,2017 年 12 月。 |
[W3C.REC-ldp-20150226] | Speicher, S.、Arwe, J. 和 A. Malhotra,「連結資料平台 1.0」,全球資訊網協會建議 REC-ldp-20150226,2015 年 2 月。 |
[json-hyper-schema] | Andrews, H. 和 A. Wright,「JSON 超綱要:JSON 超媒體註解的詞彙表」,網際網路草案 draft-handrews-json-schema-hyperschema-02,2017 年 11 月。 |
[json-schema-validation] | Wright, A.、Andrews, H. 和 B. Hutton,「JSON Schema 驗證:JSON 結構驗證的詞彙表」,網際網路草案 draft-bhutton-json-schema-validation-00,2020 年 12 月。 |
[RFC6596] | Ohye, M. 和 J. Kupke,「標準連結關係」,RFC 6596,DOI 10.17487/RFC6596,2012 年 4 月。 |
[RFC7049] | Bormann, C. 和 P. Hoffman,「簡潔二進位物件表示法 (CBOR)」,RFC 7049,DOI 10.17487/RFC7049,2013 年 10 月。 |
[RFC7231] | Fielding, R. 和 J. Reschke,「超文字傳輸協定 (HTTP/1.1):語意和內容」,RFC 7231,DOI 10.17487/RFC7231,2014 年 6 月。 |
[RFC8288] | Nottingham, M.,「網頁連結」,RFC 8288,DOI 10.17487/RFC8288,2017 年 10 月。 |
[W3C.WD-fragid-best-practices-20121025] | Tennison, J.,「片段識別符號和媒體類型定義的最佳實務」,全球資訊網協會 WD WD-fragid-best-practices-20121025,2012 年 10 月。 |
[xml-names] | Bray, T.、 Hollander, D.、 Layman, A. 和 R. Tobin,「XML 1.1 中的命名空間(第二版)」,2006 年 8 月。 |
請考慮以下綱要,它顯示如何使用「$id」來識別根綱要和各種子綱要,以及如何使用「$anchor」來定義純名稱片段識別符號。
{ "$id": "https://example.com/root.json", "$defs": { "A": { "$anchor": "foo" }, "B": { "$id": "other.json", "$defs": { "X": { "$anchor": "bar" }, "Y": { "$id": "t/inner.json", "$anchor": "bar" } } }, "C": { "$id": "urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f" } } }
以下 URI 編碼的 JSON 指標(相對於根綱要)的綱要具有以下基本 URI,並且可根據以上 5 和 9.2.1 節透過任何列出的 URI 來識別。
已經建立各種工具來根據參考("$ref")出現的方式和位置重新排列 schema 文件。本附錄討論哪些使用案例和操作符合本規範。
一組預期一起使用的 schema 資源可以組織在各自的 schema 文件中,全部在同一個 schema 文件中,或介於兩者之間的任何文件分組粒度中。
存在許多工具來執行各種參考移除。一個常見的例子是產生一個單一檔案,其中所有參考都可以在該檔案內解析。這通常是為了簡化發布,或簡化程式碼,以便 JSON Schema 函式庫的各種調用不必追蹤和載入大量資源。
只要所有靜態參考(例如 "$ref")使用解析為標準 URI 的 URI 參考,並且所有 schema 資源的根 schema 中都有一個絕對 URI 作為 "$id",就可以安全且可逆地完成此轉換。
在滿足這些條件的情況下,每個外部資源都可以複製到 "$defs" 下,而不會破壞資源的 schema 物件之間的任何參考,也不會改變驗證或註釋結果的任何方面。 "$defs" 下的 schema 名稱不會影響行為,假設它們都是唯一的,因為它們不會出現在嵌入資源的標準 URI 中。
嘗試移除所有參考並產生單一 schema 文件,在所有情況下,並不會產生與原始形式行為相同的 schema。
由於 "$ref" 現在被視為任何其他關鍵字,允許在同一個 schema 物件中使用其他關鍵字,因此在所有情況下完全支援非遞迴的 "$ref" 移除可能需要相對複雜的 schema 操作。確定或提供一組安全的 "$ref" 移除轉換並不在本規範的範圍內,因為它們不僅取決於 schema 結構,還取決於預期的用途。
考慮以下兩個 schema,它們描述了一個簡單的遞迴樹狀結構,其中樹中的每個節點都可以有一個任何類型的 "data" 欄位。第一個 schema 允許並忽略其他實例屬性。第二個 schema 更嚴格,只允許 "data" 和 "children" 屬性。還顯示了一個將 "data" 拼寫錯誤為 "daat" 的實例範例。
// tree schema, extensible { "$schema": "https://json-schema.dev.org.tw/draft/2020-12/schema", "$id": "https://example.com/tree", "$dynamicAnchor": "node", "type": "object", "properties": { "data": true, "children": { "type": "array", "items": { "$dynamicRef": "#node" } } } } // strict-tree schema, guards against misspelled properties { "$schema": "https://json-schema.dev.org.tw/draft/2020-12/schema", "$id": "https://example.com/strict-tree", "$dynamicAnchor": "node", "$ref": "tree", "unevaluatedProperties": false } // instance with misspelled field { "children": [ { "daat": 1 } ] }
當我們載入這兩個 schema 時,我們會注意到每個 schema 中都存在一個名為 "node" 的 "$dynamicAnchor"(請注意缺少 "#",因為這只是名稱),從而產生以下完整的 schema URI
此外,JSON Schema 實作會追蹤這些片段是使用 "$dynamicAnchor" 建立的事實。
如果我們將 "strict-tree" schema 套用到實例,我們將會跟隨 "$ref" 到 "tree" schema,檢查其 "children" 子 schema,並在其 "items" 子 schema 中找到 "$dynamicRef": 到 "#node"(請注意 URI 片段語法的 "#")。該參考解析為 "https://example.com/tree#node",這是一個由 "$dynamicAnchor" 建立的片段的 URI。因此,我們必須在跟隨參考之前檢查動態範圍。
此時,動態路徑為 "#/$ref/properties/children/items/$dynamicRef",動態範圍包含(從最外層範圍到最內層範圍)
由於我們正在尋找一個可以在 schema 資源中任何位置定義的純名稱片段,因此 JSON 指標片段與此檢查無關。這表示我們可以移除這些片段並消除連續的重複項,從而產生
在這種情況下,最外層資源也有一個由 "$dynamicAnchor" 定義的 "node" 片段。因此,我們不是將 "$dynamicRef" 解析為 "https://example.com/tree#node",而是將其解析為 "https://example.com/strict-tree#node"。
這樣,"tree" schema 中的遞迴會遞迴到 "strict-tree" 的根,而不是僅將 "strict-tree" 套用到實例根,而是將 "tree" 套用到實例子項。
此範例顯示每個 schema 中相同位置的兩個 "$dynamicAnchor",特別是資源根 schema。由於純名稱片段與 JSON 結構無關,因此如果其中一個或兩個節點 schema 物件被移動到 "$defs" 下,也會同樣有效。正是相符的 "$dynamicAnchor" 值告訴我們如何解析動態參考,而不是 JSON 結構中的任何關聯。
如果詞彙表旨在廣泛使用,並可能與其他詞彙表結合使用,詞彙表作者應注意避免關鍵字名稱衝突。 JSON Schema 沒有提供任何正式的命名空間系統,但也不會限制關鍵字名稱,允許使用任意數量的命名空間方法。
詞彙表可以彼此建立,例如透過定義其關鍵字相對於另一個詞彙表關鍵字的行為,或透過使用另一個詞彙表中的關鍵字及其限制或擴展的可接受值集。並非所有此類詞彙表重複使用都會產生一個與其建立的詞彙表相容的新詞彙表。詞彙表作者應清楚地說明預期的任何相容性層級。
Meta-schema 作者不應使用 "$vocabulary" 來結合為同一關鍵字定義衝突語法或語義的多個詞彙表。由於語義衝突通常無法透過 schema 驗證檢測,因此預期實作不會檢測到此類衝突。如果宣告了衝突的詞彙表,則結果行為未定義。
詞彙表作者應提供一個 meta-schema,該 schema 可以自行驗證詞彙表關鍵字的預期使用方式。此類 meta-schema 不應禁止其他關鍵字,並且不得禁止核心詞彙表中的任何關鍵字。
建議 meta-schema 作者使用 "allOf" 關鍵字參考每個詞彙表的 meta-schema,儘管其他建構 meta-schema 的機制可能適用於某些使用案例。
Meta-schema 的遞迴性質使得 "$dynamicAnchor" 和 "$dynamicRef" 關鍵字對於擴展現有的 meta-schema 特別有用,這可以在擴展驗證 meta-schema 的 JSON Hyper-Schema meta-schema 中看到。
Meta-schema 可能會施加其他限制,包括描述任何詞彙表中不存在的關鍵字,超出與宣告的詞彙表相關聯的 meta-schema 所描述的範圍。這允許將使用限制為詞彙表的子集,並允許驗證不打算重複使用的本地定義關鍵字。
但是,meta-schema 不應與它們宣告的任何詞彙表相矛盾,例如,要求與詞彙表預期的 JSON 類型不同的類型。結果行為未定義。
適用於本地使用,無需在任意實作中測試詞彙表支援的 meta-schema 可以安全地完全省略 "$vocabulary"。
此 meta-schema 明確宣告了核心和應用程式詞彙表,以及擴展詞彙表,並將它們的 meta-schema 與 "allOf" 結合使用。擴展詞彙表的 meta-schema(僅描述該詞彙表中的關鍵字)顯示在主要範例 meta-schema 之後。
主要範例 meta-schema 還透過禁止以 "unevaluated" 為前綴的關鍵字來限制未評估詞彙表的使用,這些關鍵字特別難以實作。這不會更改其他詞彙表定義的語義或關鍵字集。它只確保使用此 meta-schema 嘗試使用以 "unevaluated" 為前綴的關鍵字的 schema 將無法通過此 meta-schema 的驗證。
最後,此 meta-schema 描述了一個關鍵字 "localKeyword" 的語法,該關鍵字不是任何詞彙表的一部分。據推測,此 meta-schema 的實作者和使用者將理解 "localKeyword" 的語義。 JSON Schema 沒有定義任何表達詞彙表之外的關鍵字語義的機制,使其不適用於在理解它們的特定環境之外使用。
此 meta-schema 結合了幾個詞彙表以供一般使用。
{ "$schema": "https://json-schema.dev.org.tw/draft/2020-12/schema", "$id": "https://example.com/meta/general-use-example", "$dynamicAnchor": "meta", "$vocabulary": { "https://json-schema.dev.org.tw/draft/2020-12/vocab/core": true, "https://json-schema.dev.org.tw/draft/2020-12/vocab/applicator": true, "https://json-schema.dev.org.tw/draft/2020-12/vocab/validation": true, "https://example.com/vocab/example-vocab": true }, "allOf": [ {"$ref": "https://json-schema.dev.org.tw/draft/2020-12/meta/core"}, {"$ref": "https://json-schema.dev.org.tw/draft/2020-12/meta/applicator"}, {"$ref": "https://json-schema.dev.org.tw/draft/2020-12/meta/validation"}, {"$ref": "https://example.com/meta/example-vocab", ], "patternProperties": { "^unevaluated": false }, "properties": { "localKeyword": { "$comment": "Not in vocabulary, but validated if used", "type": "string" } } }
此 meta-schema 僅描述單一擴展詞彙表。
{ "$schema": "https://json-schema.dev.org.tw/draft/2020-12/schema", "$id": "https://example.com/meta/example-vocab", "$dynamicAnchor": "meta", "$vocabulary": { "https://example.com/vocab/example-vocab": true, }, "type": ["object", "boolean"], "properties": { "minDate": { "type": "string", "pattern": "\d\d\d\d-\d\d-\d\d", "format": "date", } } }
如上所示,即使在一般用途 meta-schema 的 "allOf" 中參考的每個單一詞彙表 meta-schema 都宣告了其對應的詞彙表,這個新的 meta-schema 也必須重新宣告它們。
組合了核心和驗證規範定義的所有詞彙表,以及組合了這些規範以及 Hyper-Schema 規範定義的所有詞彙表的標準 meta-schema 展示了其他複雜的組合。這些 meta-schema 的 URI 分別可以在驗證和 Hyper-Schema 規範中找到。
雖然一般用途 meta-schema 可以驗證 "minDate" 的語法,但詞彙表定義了 "minDate" 語義含義背後的邏輯。如果沒有對語義的理解(在此範例中,實例值必須是等於或晚於 schema 中作為關鍵字值提供的日期的日期),實作只能驗證語法使用。在這種情況下,這表示驗證它是一個日期格式化的字串(使用 "pattern" 來確保即使 "format" 僅作為註釋時也進行驗證,如 驗證規範中所述)。
雖然參考的存在預期對驗證結果是透明的,但程式碼產生器和 UI 渲染器等生成用例通常認為參考在語義上很重要。
為了明確表示這種針對特定用例的語意,最佳實踐是在同一個綱要物件中,與 "$ref" 等參考關鍵字一起建立一個註解關鍵字。
例如,這裡有一個假設的關鍵字,用於決定程式碼產生器是否應將參考目標視為一個獨立的類別,以及這些類別之間的關係。請注意,此範例僅用於說明目的,並非旨在提出一個功能性的程式碼產生關鍵字。
{ "allOf": [ { "classRelation": "is-a", "$ref": "classes/base.json" }, { "$ref": "fields/common.json" } ], "properties": { "foo": { "classRelation": "has-a", "$ref": "classes/foo.json" }, "date": { "$ref": "types/dateStruct.json", } } }
在這裡,這個綱要代表某種類型的物件導向類別。"allOf" 中的第一個參考被註記為基底類別。第二個則未指定類別關係,這表示程式碼產生器應將目標的定義與此定義合併,如同未涉及任何參考一樣。
查看屬性,「foo」被標記為物件組合,而「date」屬性則否。它僅是一個帶有子欄位的欄位,而非一個獨立類別的實例。
這種使用方式要求註解必須與參考位於同一個物件中,而該物件必須可識別為參考。
感謝 Gary Court、Francis Galiegue、Kris Zyp 和 Geraint Luff 對 JSON Schema 初稿的貢獻。
感謝 Jason Desrosiers、Daniel Perrett、Erik Wilde、Evgeny Poberezkin、Brad Bowman、Gowry Sankar、Donald Pipowitch、Dave Finlay、Denis Laxalde、Phil Sturgeon、Shawn Silverman 和 Karen Etheridge 為文件提交內容和修補程式。
[CREF13]本節將在離開 Internet-Draft 狀態前移除。