網際網路工程任務組 A. Wright,編輯
網際網路草案
預期狀態:資訊性 H. Andrews,編輯
到期日:2020 年 3 月 20 日
B. Hutton,編輯
Wellcome Sanger 研究院
G. Dennis
2019 年 9 月 17 日

JSON Schema:描述 JSON 文件的一種媒體類型
draft-handrews-json-schema-02

摘要

JSON Schema 定義了媒體類型 "application/schema+json",這是一種基於 JSON 的格式,用於描述 JSON 資料的結構。JSON Schema 聲明了 JSON 文件必須具備的外觀、從中提取資訊的方法,以及如何與其互動。除了 "application/json" 文件所能提供的功能外,"application/schema-instance+json" 媒體類型還提供了與 "application/schema+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/。

網際網路草案是有效期最多六個月的草案文件,並且可能隨時被其他文件更新、取代或廢棄。將網際網路草案用作參考資料或將其引用為「進行中的工作」是不恰當的。

本網際網路草案將於 2020 年 3 月 20 日到期。

著作權聲明

著作權 (c) 2019 IETF Trust 和被認定為文件作者的人士。保留所有權利。

本文件受 BCP 78 和 IETF Trust 的關於 IETF 文件之法律規定 (https://trustee.ietf.org/license-info) 的約束,該規定於本文件發布之日生效。請仔細審閱這些文件,因為它們描述了您對本文件的權利和限制。從本文件中提取的程式碼組件必須包含簡化的 BSD 授權條款文字,如 Trust 法律規定的第 4.e 節所述,並且不提供簡化的 BSD 授權中所述的擔保。


目錄

1. 簡介

JSON Schema 是一種 JSON 媒體類型,用於定義 JSON 資料的結構。JSON Schema 旨在定義 JSON 資料的驗證、文件、超連結導覽和互動控制。

本規範定義了 JSON Schema 的核心術語和機制,包括通過參考指向另一個 JSON Schema、取消參照 JSON Schema 參考、指定正在使用的詞彙以及定義預期的輸出。

其他規範定義了執行有關驗證、連結、註解、導覽和互動的斷言的詞彙。

2. 慣例和術語

本文檔中的關鍵字「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、「MAY」和「OPTIONAL」應按照 RFC 2119 中所述進行解釋。

本文檔中的術語「JSON」、「JSON 文字」、「JSON 值」、「成員」、「元素」、「物件」、「陣列」、「數字」、「字串」、「布林」、「true」、「false」和「null」應按照 RFC 8259 中的定義進行解釋。

3. 概述

本文檔提出了一種新的媒體類型「application/schema+json」,用於識別描述 JSON 資料的 JSON Schema。它還提出了一種額外的可選媒體類型「application/schema-instance+json」,以提供額外的整合功能。JSON Schema 本身就是 JSON 文件。此規範及相關規範定義了允許作者以多種方式描述 JSON 資料的關鍵字。

JSON Schema 使用關鍵字來斷言 JSON 實例的約束或使用其他資訊註解這些實例。其他關鍵字用於將斷言和註解應用於更複雜的 JSON 資料結構,或根據某種條件應用。

為了方便重複使用,關鍵字可以組織成詞彙。詞彙由關鍵字清單及其語法和語義組成。

JSON Schema 可以通過定義其他詞彙進行擴展,或者通過在任何詞彙之外定義其他關鍵字進行較不正式的擴展。無法識別的個別關鍵字會被忽略,而對於無法識別的詞彙,可以在宣告正在使用的詞彙時控制其行為。

本文檔定義了任何實作都必須支援且無法停用的核心詞彙。它的關鍵字都以「$」字元作為前綴,以強調其必要性。此詞彙對於「application/schema+json」媒體類型的運作至關重要,並且用於引導其他詞彙的載入。

此外,本文件定義了一組「建議」的關鍵字詞彙,用於有條件地應用子 schema,以及將子 schema 應用於物件和陣列的內容。無論這些 schema 的目的是用於斷言驗證、註解,還是兩者兼具,撰寫非平凡 JSON 實例的 schema 時,都必須使用此詞彙或非常相似的詞彙。雖然此額外詞彙並非必要核心詞彙的一部分,但為了達到最大的互操作性,本文件仍將其納入,並強烈建議使用。

用於結構驗證或超媒體註解等目的的進階詞彙定義於其他文件中。

4. 定義

4.1. JSON 文件

JSON 文件是一種資訊資源(一系列的八位元組),以 application/json 媒體類型描述。

在 JSON Schema 中,「JSON 文件」、「JSON 文字」和「JSON 值」等術語可互換使用,因為它們定義的資料模型相同。

JSON Schema 僅針對 JSON 文件定義。但是,任何可以解析為或根據 JSON Schema 資料模型處理的文件或記憶體結構,都可以根據 JSON Schema 來解釋,包括像 CBOR 這樣的媒體類型。

4.2. 實例

應用 schema 的 JSON 文件稱為「實例」。

4.2.1. 實例資料模型

JSON Schema 根據資料模型解釋文件。根據此資料模型解釋的 JSON 值稱為「實例」。

實例有六種原始類型之一,並且根據類型具有一系列可能的值。

null
JSON 的 "null" 產生式
boolean
來自 JSON "true" 或 "false" 產生式的 "true" 或 "false" 值
object
來自 JSON "object" 產生式的一組無序屬性,將字串映射到實例
array
來自 JSON "array" 產生式的一組有序實例列表
number
來自 JSON "number" 產生式的任意精度、十進制數值
string
來自 JSON "string" 產生式的一串 Unicode 碼位

因此,包括資料模型中相等數值的不同詞彙表示在內的空白和格式問題,都超出了 JSON Schema 的範圍。希望處理詞彙表示差異的 JSON Schema 詞彙,應該定義關鍵字來精確解釋資料模型中的格式化字串,而不是依賴於原始 JSON 表示的 Unicode 字元。

由於物件不能有兩個具有相同鍵的屬性,因此在單個物件中嘗試定義兩個具有相同鍵("string" 產生式)的屬性("member" 產生式)的 JSON 文件行為是未定義的。

請注意,JSON Schema 詞彙可以自由定義它們自己的擴展類型系統。這不應與此處定義的核心資料模型類型混淆。例如,「integer」是詞彙可以定義為關鍵字值的合理類型,但資料模型並未區分整數和其他數字。

4.2.2. 實例媒體類型

JSON Schema 旨在完全適用於 "application/json" 文件,以及使用 "+json" 結構化語法後綴的媒體類型。

每個媒體類型都會定義一些對處理 schema 有用的功能,即媒體類型參數以及 URI 片段識別符號語法和語義。這些功能分別在內容協商和計算實例中特定位置的 URI 時很有用。

本規範定義了 "application/schema-instance+json" 媒體類型,以便讓實例作者可以充分利用這些用途的參數和片段識別符號。

4.2.3. 實例相等性

當且僅當兩個 JSON 實例屬於同一類型,並根據資料模型具有相同的值時,才稱它們相等。具體來說,這意味著

此定義暗示陣列的長度必須相同,物件必須具有相同數量的成員,物件中的屬性是無序的,沒有辦法定義具有相同鍵的多個屬性,而且僅格式差異(縮排、逗號位置、尾隨零)是無關緊要的。

4.3. JSON Schema 文件

JSON Schema 文件,或簡稱為 schema,是用於描述實例的 JSON 文件。schema 本身可以被解釋為實例,但應始終使用 "application/schema+json" 媒體類型,而不是 "application/schema-instance+json"。"application/schema+json" 媒體類型的定義是提供 "application/schema-instance+json" 所提供的媒體類型參數和片段識別符號語法和語義的超集。

JSON Schema 必須是物件或布林值。

4.3.1. JSON Schema 物件和關鍵字

應用於實例的物件屬性稱為關鍵字或 schema 關鍵字。廣義來說,關鍵字可分為四類

識別符號
透過設定 schema 的標準 URI 和/或變更基本 URI 的判斷方式來控制 schema 識別
斷言
應用於實例時產生布林值結果
註解
將資訊附加到實例供應用程式使用
應用器
將一個或多個子 schema 應用於實例中的特定位置,並結合或修改其結果
保留位置
不直接影響結果,但為特定目的保留位置以確保互操作性

關鍵字可以屬於多個類別,但應用器應該只根據其子 schema 的結果產生斷言結果。它們不應該定義獨立於其子 schema 的額外約束。

擴展關鍵字,是指在本文件及其相關文件之外定義的關鍵字,可以自由定義其他行為。

JSON Schema 可以包含非 schema 關鍵字的屬性。應該忽略未知的關鍵字。

空的 schema 是沒有屬性或只有未知屬性的 JSON Schema。

4.3.2. 布林 JSON Schema

布林值 schema "true" 和 "false" 是簡單的 schema,無論實例值為何,都會始終產生自身作為斷言結果。它們永遠不會產生註解結果。

這些布林 schema 的存在是為了闡明 schema 作者的意圖並促進 schema 處理最佳化。它們的行為與以下 schema 物件完全相同(其中 "not" 是本文件中定義的子 schema 應用詞彙的一部分)。

true
始終通過驗證,如同空的 schema {}
false
始終驗證失敗,如同 schema { "not": {} }

雖然空的 schema 物件是明確的,但有許多可能的 schema 等效於 "false"。使用布林值可確保人類讀者和實作都能清楚了解意圖。

4.3.3. Schema 詞彙

schema 詞彙,或簡稱為詞彙,是一組關鍵字、它們的語法和語義。詞彙通常圍繞特定目的組織。JSON Schema 的不同用途,如驗證、超媒體或使用者介面產生,將涉及不同的詞彙集。

詞彙是 JSON Schema 中可重複使用的主要單位,因為 schema 作者可以指示處理 schema 時需要或可選哪些詞彙。由於詞彙在 meta-schema 中由 URI 識別,因此通用實作可以載入擴展來支援先前未知的詞彙。雖然可以在任何詞彙之外支援關鍵字,但沒有類似的機制來指示個別關鍵字的使用。

4.3.4. Meta-Schemas

描述 schema 本身的 schema 稱為 meta-schema。Meta-schema 用於驗證 JSON Schema 並指定它們正在使用的詞彙。

通常,meta-schema 將指定一組詞彙,並驗證符合這些詞彙語法的 schema。然而,meta-schema 和詞彙是分開的,以便讓 meta-schema 能夠比詞彙規範要求的更嚴格或更寬鬆地驗證 schema 一致性。Meta-schema 也可能描述和驗證不屬於正式詞彙的其他關鍵字。

4.3.5. 根 Schema 和子 Schema 和資源

JSON Schema 資源是 標準絕對 URI 識別的 schema。

根 schema 是包含相關整個 JSON 文件的 schema。根 schema 始終是 schema 資源,其中 URI 的判斷方式如第 8.2.1 節所述。

一些關鍵字本身採用 schema,允許巢狀 JSON Schema

{
    "title": "root",
    "items": {
        "title": "array item"
    }
}

                        

在此範例文件中,標題為「array item」的 schema 是子 schema,而標題為「root」的 schema 是根 schema。

與根 schema 一樣,子 schema 也是物件或布林值。

如第 8.2.2 節所述,JSON Schema 文件可以包含多個 JSON Schema 資源。在未經限定的情況下使用時,「根 schema」一詞指的是文件的根 schema。在某些情況下,會討論資源根 schema。資源的根 schema 是其最上層的 schema 物件,如果將資源提取到獨立的 JSON Schema 文件中,則該物件也將是文件的根 schema。

5. 片段識別符號

根據 [RFC6839] 的 3.1 節,為任何 +json 媒體類型指定的片段識別符號語法和語義應與 "application/json" 所指定的相同。(在本文件發佈時,尚未為 "application/json" 定義片段識別語法。)

此外,"application/schema+json" 媒體類型支援兩種片段識別符號結構:純名稱和 JSON 指標。"application/schema-instance+json" 媒體類型支援一種片段識別符號結構:JSON 指標。

使用 JSON 指標作為 URI 片段識別符號的方法在 RFC 6901 中描述。對於支援兩種片段識別符號語法的 "application/schema+json",符合 JSON 指標語法的片段識別符號(包括空字串)必須解釋為 JSON 指標片段識別符號。

根據 W3C 的 片段識別符號最佳實務,"application/schema+json" 中的純名稱片段識別符號保留用於參照本機命名的 schema。所有不符合 JSON 指標語法的片段識別符號都必須解釋為純名稱片段識別符號。

"$anchor" 關鍵字一節中指定了在 "application/schema+json" 文件中定義和參照純名稱片段識別符號的方法。

6. 一般考量

6.1. JSON 值範圍

實例可以是 JSON 定義的任何有效 JSON 值。JSON Schema 不對類型施加任何限制:JSON Schema 可以描述任何 JSON 值,包括 null 等。

6.2. 程式語言獨立性

JSON Schema 與程式語言無關,並且支援資料模型中描述的完整值範圍。但是請注意,某些語言和 JSON 解析器可能無法在記憶體中表示 JSON 可描述的完整值範圍。

6.3. 數學整數

一些程式語言和解析器使用不同的內部表示來表示浮點數和整數。

為了保持一致性,整數 JSON 數字不應編碼為帶有小數部分。

6.4. 正規表示式

關鍵字可以使用正規表示式來表達約束,或限制實例值為正規表示式。這些正規表示式應根據 ECMA 262, section 15.10.1 中描述的正規表示式方言有效。

此外,考慮到正規表示式結構支援的高度差異,schema 作者應將自己限制在以下正規表示式符號:

最後,實作絕不能將正規表示式視為錨定,無論是在開頭還是結尾。這表示,例如,模式 "es" 會匹配 "expression"。

6.5. 擴充 JSON Schema

任何實體都可以定義額外的 schema 關鍵字和 schema 詞彙。除非有明確協議,否則 schema 作者不應期望未明確記錄此類支援的實作支援這些額外的關鍵字和詞彙。實作應忽略它們不支援的關鍵字。

實作可以提供註冊或載入它們不直接支援的詞彙的處理常式的功能。註冊和實作此類處理常式的確切機制取決於實作。

7. 關鍵字行為

JSON Schema 關鍵字可分為幾個常見的行為類別。斷言驗證實例是否滿足約束,產生布林值結果。註解附加應用程式可能以任何他們認為合適的方式使用的資訊。應用器將子 schema 應用於實例的部分,並組合它們的結果。

擴充關鍵字應保留在這些類別中,請記住註解特別靈活。通常,複雜行為最好根據註解資料委派給應用程式,而不是直接實作為 schema 關鍵字。然而,擴充關鍵字可以為特殊目的定義其他行為。

針對 schema 評估實例涉及針對實例中適當的位置處理 schema 中的所有關鍵字。通常,應用器關鍵字會被處理直到到達沒有應用器(因此沒有子 schema)的 schema 物件。實例中適當的位置會針對 schema 物件中的斷言和註解關鍵字進行評估,並且它們的結果會根據應用器的規則收集到父 schema 中。

一旦其所有子 schema 都被評估,父 schema 物件的評估就可以完成,儘管在某些情況下,由於斷言結果,評估可能會提前結束。當收集註解時,由於需要檢查所有子 schema 以進行註解收集(包括那些無法進一步改變斷言結果的子 schema),因此某些斷言結果提前結束是不可能的。

7.1. 詞法範圍和動態範圍

雖然大多數 JSON Schema 關鍵字可以單獨評估,或者最多只需要考慮同一 schema 物件中相鄰關鍵字的值或結果,但有些關鍵字具有更複雜的行為。

關鍵字的詞法範圍由物件和陣列的巢狀 JSON 資料結構決定。最大的此類範圍是整個 schema 文件。最小的範圍是沒有子 schema 的單個 schema 物件。

可以定義具有部分值的關鍵字,例如 URI 參考,必須根據另一個值(例如另一個 URI 參考或完整 URI)解析,該值是透過 JSON 文件的詞法結構找到的。"$id" 核心關鍵字和 "base" JSON Hyper-Schema 關鍵字就是此類行為的範例。此外,此規格中的 "$ref" 和 "$recursiveRef" 以這種方式解析其值,儘管它們不會更改進一步值的解析方式。

請注意,某些關鍵字(例如 "$schema")適用於整個 schema 文件的詞法範圍,因此必須僅出現在 schema 資源的根 schema 中。

其他關鍵字可以考慮在評估 schema 期間存在的動態範圍,通常與實例文件一起考慮。最外層的動態範圍是開始處理的 schema 文件的根 schema。從此根 schema 到任何特定關鍵字的路徑(包括可能已解析的任何 "$ref" 和 "$recursiveRef" 關鍵字)被視為關鍵字的「驗證路徑」。 [CREF1]或者這應該是開始處理的 schema 物件,即使它不是根?這對於僅允許在根 schema 中使用 "$recursiveAnchor" 但在子 schema 中開始處理的情況有一些影響。

詞法範圍和動態範圍會對齊,直到遇到參考關鍵字。雖然遵循參考關鍵字會將處理從一個詞法範圍移動到另一個詞法範圍,但從動態範圍的角度來看,遵循參考與下降到作為值存在的子 schema 沒有什麼不同。參考遠側透過動態範圍解析資訊的關鍵字將認為參考的原始側是它們的動態父級,而不是檢查本地詞法封閉的父級。

動態範圍的概念主要用於 "$recursiveRef" 和 "$recursiveAnchor",應被視為進階功能,在定義額外的關鍵字時應謹慎使用。它也會在報告錯誤和收集註解時出現,因為有可能使用不同的動態範圍重複訪問相同的詞法範圍。在這種情況下,重要的是告知使用者產生錯誤或註解的動態路徑。

7.2. 關鍵字互動

關鍵字行為可以根據 子 schema 和/或相鄰關鍵字的註解結果定義。此類關鍵字不得導致循環相依性。關鍵字可以根據同一 schema 物件中是否存在另一個關鍵字來修改其行為。

7.3. 預設行為

遺失的關鍵字不得產生錯誤的斷言結果,不得產生註解結果,也不得導致任何其他 schema 作為其自身行為定義的一部分進行評估。然而,鑑於遺失的關鍵字不貢獻註解,缺少註解結果可能會間接改變其他關鍵字的行為。

在某些情況下,關鍵字的遺失關鍵字斷言行為與某個值產生的斷言行為相同,並且關鍵字定義應在已知的情況下記錄此類值。然而,即使產生預設行為的值在存在時會產生註解結果,預設行為仍然不得產生註解。

由於註解收集在計算和記憶體方面都可能增加顯著成本,因此實作可能會選擇不使用此功能。已知實作具有取決於註解結果的斷言或應用器行為的關鍵字必須被視為錯誤,除非有產生相同行為的替代實作可用。此類關鍵字應在適當的情況下描述合理的替代方法。此方法在本文檔中的 "additionalItems" 和 "additionalProperties" 關鍵字中得到了示範。

7.4. 識別碼

識別碼設定 schema 的規範 URI,或影響 參考中此類 URI 的解析方式,或兩者皆是。本文檔中定義的核心詞彙定義了幾個識別關鍵字,最值得注意的是 "$id"。

在處理實例時,規範 schema URI 不得更改,但影響 URI 參考解析的關鍵字可能具有僅在執行階段完全確定的行為。

雖然可以自訂識別碼關鍵字,但詞彙設計人員應注意不要中斷核心關鍵字的運作。例如,本規範中的 "$recursiveAnchor" 關鍵字將其 URI 解析效果限制為匹配的 "$recursiveRef" 關鍵字,而不干擾 "$ref"。

7.5. 應用器

應用器允許建構比單個 schema 物件可以完成的更複雜的 schema。針對 schema 文件評估實例是透過將 根 schema 應用於完整的實例文件開始的。從那裡,使用稱為應用器的關鍵字來決定應用哪些額外的 schema。此類 schema 可以就地應用於當前位置,或應用於子位置。

要應用的 schema 可以作為構成關鍵字值全部或一部分的子 schema 存在。或者,應用器可以參考同一 schema 文件中或不同文件中的其他 schema。識別此類參考 schema 的機制由關鍵字定義。

應用器關鍵字還定義如何修改和/或組合子 schema 或參考 schema 布林值斷言結果,以產生應用器的布林值結果。應用器可以將任何布林值邏輯運算應用於子 schema 的斷言結果,但不得引入其自身的新斷言條件。

註解結果會根據每個註解關鍵字指定的規則進行組合。

7.5.1. 參考和引用 Schema

第 7.5 節中所述,應用器關鍵字可以參考要應用的 schema,而不是將其作為子 schema 包含在應用器的值中。在這種情況下,正在應用的 schema 被稱為參考 schema,而包含應用器關鍵字的 schema 是引用 schema。

雖然根 schema 和子 schema 是基於 schema 在 schema 文件中的位置的靜態概念,但參考和引用 schema 是動態的。在針對 schema 評估實例期間,不同的 schema 對可能會發現自己處於不同的參考和引用安排中。

對於某些按參考應用器(例如 "$ref"),可以透過對 schema 文件的詞法範圍進行靜態分析來確定參考 schema。其他(例如 "$recursiveRef" 和 "$recursiveAnchor")可能使用動態範圍,因此只能在評估具有實例的 schema 的過程中解析。

7.6. 斷言

JSON Schema 可用於對 JSON 文件聲明約束,這些約束會判斷文件是否通過驗證。此方法可用於驗證是否符合約束,或記錄滿足約束所需的要求。

JSON Schema 實作在評估實例是否符合 schema 斷言時,會產生單一的布林值結果。

實例只能因為 schema 中存在的斷言而驗證失敗。

7.6.1. 斷言與實例基本類型

大多數斷言只會約束特定基本類型中的值。當實例的類型不是關鍵字所針對的類型時,則該實例會被視為符合該斷言。

例如,來自配套驗證詞彙的 "maxLength" 關鍵字:只會限制某些(過長的)字串有效。如果實例是數字、布林值、null、陣列或物件,則它會符合此斷言。

此行為允許關鍵字更輕鬆地用於可以有多種基本類型的實例。配套驗證詞彙也包含一個 "type" 關鍵字,可以獨立地將實例限制為一個或多個基本類型。這允許簡潔地表達使用案例,例如可能返回特定長度的字串或 null 值的函式。

{
    "type": ["string", "null"],
    "maxLength": 255
}

                        

如果 "maxLength" 也將實例類型限制為字串,則表達起來會相當麻煩,因為如此一來,寫成的範例實際上不允許 null 值。每個關鍵字都會單獨評估,除非另有明確規定,因此如果 "maxLength" 將實例限制為字串,則在 "type" 中包含 "null" 不會有任何實際作用。

7.7. 註解

每當實例根據包含註解的 schema 物件及其所有父 schema 物件進行驗證時,JSON Schema 可以使用資訊註解實例。該資訊可以是簡單的值,也可以根據實例內容計算得出。

註解會附加到實例中的特定位置。由於許多子 schema 可以應用於任何單一位置,因此註解關鍵字需要指定對具有不同值的關鍵字的多個適用情況進行任何不尋常的處理。

與斷言結果不同,註解資料可以採用多種形式,提供給應用程式自行決定如何使用。JSON Schema 實作預期不會代表應用程式使用收集到的資訊。

除非另有說明,否則註解關鍵字的註解值就是關鍵字的值。但是,也可能存在其他行為。例如,JSON Hyper-Schema 的 "links" 關鍵字是一個複雜的註解,它會產生一個部分基於實例資料的值。

雖然斷言可以進行「短路」評估,但收集註解需要檢查適用於實例位置的所有 schema,即使它們無法變更整體斷言結果。唯一的例外是,如果 schema 物件的子 schema 未通過驗證,則可以跳過這些子 schema,因為失敗的 schema 不會保留註解。

7.7.1. 收集註解

註解由明確定義註解收集行為的關鍵字收集。請注意,布林 schema 無法產生註解,因為它們不使用關鍵字。

收集的註解必須包含以下資訊

如果同一關鍵字從多個 schema 位置將值附加到同一個實例位置,且註解定義了組合這些值的過程,則組合值也必須與該實例位置關聯。本規範中描述的輸出格式(其中包含註解資訊)符合此要求。

7.7.1.1. 區分多個值

應用程式可以根據提供值的 schema 位置,決定要使用哪個多個註解值。這樣做是為了實現靈活的使用方式。收集 schema 位置有助於此類使用。

例如,考慮這個 schema,它使用驗證規範中的註解和斷言

請注意,為了清楚起見,某些行已換行。

{
    "title": "Feature list",
    "type": "array",
    "items": [
        {
            "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 位置在哪裡,應用程式都可能會認為存在兩個不同的 "default" 值是一種錯誤。

7.7.1.2. 註解與斷言

產生 false 斷言結果的 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" 會被保留,因為實例通過了字串類型斷言。

7.7.1.3. 註解與應用程式

除了可能定義它們自己的註解結果之外,應用程式關鍵字還會聚合在其子 schema 或參考的 schema 中收集的註解。聚合註解值的規則由每個註解關鍵字定義,不受用於組合斷言結果的邏輯直接影響。

7.8. 保留位置

第四類關鍵字只是保留一個位置,用於保存可重複使用的元件或 schema 作者感興趣的數據,這些元件或數據不適合重複使用。這些關鍵字不影響驗證或註解結果。它們在核心詞彙中的目的是確保某些用途的位置可用,不會被擴充關鍵字重新定義。

雖然這些關鍵字不會直接影響結果,但如 8.2.4.4 節所述,未識別的擴充關鍵字(為可重複使用 schema 保留位置)在某些情況下可能會與參考產生不良互動。

8. JSON Schema 核心詞彙

本節中宣告的關鍵字(均以 "$" 開頭)構成 JSON Schema 核心詞彙。這些關鍵字是處理任何 schema 或 meta-schema(包括跨多個文件分割的 schema 或 meta-schema)所必需的,或者存在於為需要保證互通性的目的保留關鍵字。

為了引導後續詞彙的處理,必須始終將核心詞彙視為強制性的。使用 "$vocabulary" 關鍵字宣告正在使用的詞彙的 meta-schema 必須明確列出核心詞彙,其值必須為 true,表示它是必需的。

此詞彙(且僅限於此詞彙)的 false 值行為未定義,當存在 "$vocabulary" 但未包含核心詞彙時的行為也未定義。但是,建議實作偵測這些情況,並在發生這些情況時引發錯誤。宣告 meta-schema 可選擇性地使用核心是沒有意義的。

未使用 "$vocabulary" 的 meta-schema 必須被視為需要核心詞彙,如同其 URI 存在且值為 true 一樣。

核心詞彙的目前 URI 為:<https://json-schema.dev.org.tw/draft/2019-09/vocab/core>

對應 meta-schema 的目前 URI 為:<https://json-schema.dev.org.tw/draft/2019-09/meta/core>

雖然 "$" 前綴並非正式保留給核心詞彙,但建議擴充關鍵字(在詞彙中或其他情況下)以 "$" 以外的字元開頭,以避免未來可能發生衝突。

8.1. Meta-Schema 和詞彙

meta-schema 和詞彙這兩個概念用於告知實作如何解釋 schema。每個 schema 都有一個 meta-schema,可以使用 "$schema" 關鍵字宣告。

meta-schema 有兩個用途

宣告正在使用的詞彙
當 "$vocabulary" 關鍵字出現在 meta-schema 中時,它會宣告哪些詞彙可用於參考該 meta-schema 的 schema 中。詞彙定義了關鍵字語意及其一般語法。
描述有效的 schema 語法
schema 必須根據其 meta-schema 成功驗證,meta-schema 會約束可用關鍵字的語法。所描述的語法預期與宣告的詞彙相容;雖然可以描述不相容的語法,但這樣的 meta-schema 不太可能有用。

元架構與詞彙表是分開的,這樣可以讓詞彙表以不同的方式組合,並讓元架構的作者可以施加額外的約束,例如禁止某些關鍵字,或執行異常嚴格的語法驗證,如同在開發和測試週期中可能進行的那樣。每個詞彙表通常會識別一個僅包含該詞彙表關鍵字的元架構。

元架構的編寫是 JSON Schema 的進階用法,因此元架構功能的設計強調彈性而非簡潔性。

8.1.1. 「$schema」關鍵字

「$schema」關鍵字既用作 JSON Schema 功能集的識別符,也用作資源的識別符,該資源本身是一個 JSON Schema,描述了為此特定功能集編寫的有效架構集。

此關鍵字的值必須是 URI(包含 scheme),且此 URI 必須正規化。目前的架構必須符合此 URI 所識別的元架構。

如果此 URI 識別可檢索的資源,該資源的媒體類型應為「application/schema+json」。

「$schema」關鍵字應在資源根架構中使用。它不得出現在資源子架構中。如果根架構中缺少此關鍵字,則結果行為由實作定義。

如果單一文件中存在多個架構資源,則所有架構資源的「$schema」值應相同。同一架構文件中「$schema」的值不同,其結果由實作定義。[CREF2]在同一文件中使用多個「$schema」關鍵字,表示功能集以及行為可以在文件中變更。這將需要解決許多尚未明確定義的實作問題。因此,雖然僅在根架構中使用「$schema」的模式可能仍然是架構編寫的最佳實務,但實作行為可能會在未來的草案中修訂或放寬。 [CREF3]對嵌入式架構資源的例外情況是允許將多個架構資源捆綁到單一架構文件中,而無需變更其內容,如本規範稍後所述。

此屬性的值在本文檔和其他文檔中,以及由其他方定義。

8.1.2. 「$vocabulary」關鍵字

「$vocabulary」關鍵字在元架構中用於識別該元架構所描述的架構中可用的詞彙表。它也用於指示每個詞彙表是必要還是可選的,意思是實作必須理解必要的詞彙表才能成功處理架構。

此關鍵字的值必須是一個物件。物件中的屬性名稱必須是 URI(包含 scheme),且此 URI 必須正規化。每個作為屬性名稱出現的 URI 都會識別一組特定的關鍵字及其語意。

URI 可能是 URL,但可檢索資源的性質目前未定義,保留供未來使用。詞彙表作者可以使用詞彙表規格的 URL,以人類可讀的媒體類型(例如 text/html 或 text/plain)作為詞彙表 URI。[CREF4]詞彙表文件可能會在即將發布的草案中新增。目前,識別關鍵字集被認為是足夠的,因為這與元架構驗證一起,是目前「詞彙表」的運作方式。任何未來的詞彙表文件格式都將指定為 JSON 文件,因此在此期間使用 text/html 或其他非 JSON 格式不會產生任何未來歧義。

物件屬性的值必須是布林值。如果值為 true,則不識別該詞彙表的實作必須拒絕處理任何使用「$schema」宣告此元架構的架構。如果值為 false,則不識別該詞彙表的實作應繼續處理此類架構。

根據 6.5,無法識別的關鍵字應忽略。對於由無法識別的詞彙表定義的關鍵字,情況仍然如此。目前無法區分詞彙表中定義的無法識別的關鍵字與不屬於任何詞彙表的關鍵字。

「$vocabulary」關鍵字應在任何旨在用作元架構的架構文件的根架構中使用。它不得出現在子架構中。

在未作為元架構處理的架構文件中,「$vocabulary」關鍵字必須被忽略。這允許驗證元架構 M 是否符合其自身的元架構 M',而無需驗證器理解 M 所宣告的詞彙表。

8.1.2.1. 預設詞彙表

如果缺少「$vocabulary」,則實作可以根據元架構(如果從參考架構的「$schema」關鍵字的 URI 值中識別出)來決定行為。這是如何在詞彙表存在之前識別行為(例如 Hyper-Schema 用法)的方式。

如果架構所參考的元架構無法識別或遺失,則行為由實作定義。如果實作繼續處理架構,則必須假設使用核心詞彙表。如果實作是為特定目的而建立的,則應假設使用最適用於該目的的所有詞彙表。

例如,作為驗證器的實作應假設使用本規範和相關的驗證規範中的所有詞彙表。

8.1.2.2. 詞彙表的不可繼承性

請注意,「$vocabulary」的處理限制表示,使用「$ref」或類似關鍵字參考其他元架構的元架構不會自動繼承其他元架構的詞彙表宣告。所有此類宣告都必須在每個旨在用作元架構的架構文件的根中重複。這在 範例元架構 中示範。[CREF5]此要求允許實作在每個元架構的單一位置找到所有詞彙表需求資訊。由於架構的可擴展性表示,透過參考組合更精細的元架構的方式可能有無數種,因此要求實作預期所有可能性並在參考的元架構中搜尋詞彙表將過於繁重。

8.1.3. 元架構和詞彙表 URI 的更新

更新的詞彙表和元架構 URI 可以在規格草案之間發布,以更正錯誤。實作應考慮在本規格草案之後和下一個規格草案之前註明日期的 URI,以表示與此處列出的語法和語意相同。

8.1.4. 偵測元架構

如果實作檢查架構的原因是因為它被另一個架構的「$schema」關鍵字識別為元架構,則實作必須將該架構識別為元架構。這表示單一架構文件有時可能被視為常規架構,而有時則被視為元架構。

在檢查作為自身元架構的架構的情況下,當實作開始將其作為常規架構處理時,它會按照這些規則進行處理。但是,當第二次因檢查其自身的「$schema」值而載入時,它會被視為元架構。因此,在一個會期中,同一個文件會以兩種方式處理。

實作可以允許明確將架構作為元架構傳遞,以用於實作特定的目的,例如預先載入常用的元架構並預先檢查其詞彙表支援需求。元架構作者不得期望此類功能在不同實作之間具有互通性。

8.2. 基礎 URI、錨點和取消參考

為了區分廣大生態系統中的架構,架構由 URI 識別,並且可以透過指定其 URI 來嵌入對其他架構的參考。

有幾個關鍵字可以接受相對的 URI 參考,或用於建構相對 URI 參考的值。對於這些關鍵字,有必要建立基礎 URI 以解析參考。

8.2.1. 初始基礎 URI

RFC3986 第 5.1 節定義了如何判斷文件的預設基礎 URI。

簡而言之,架構的初始基礎 URI 是找到它的 URI,無論是網路位置、本地檔案系統,還是任何其他可以透過任何已知 scheme 的 URI 識別的情況。

如果架構文件沒有使用「$id」(嵌入在內容中)定義明確的基礎 URI,則基礎 URI 是根據 RFC 3986 第 5 節確定的。

如果沒有已知的來源,或者來源沒有已知的 URI scheme,則可以使用 RFC 3986 第 5.1.4 節中所述的適當實作特定預設 URI。建議實作記錄他們假設的任何預設基礎 URI。

除非下一節中描述的「$id」關鍵字出現在根架構中,否則此基礎 URI 應被視為架構文件根架構資源的標準 URI。

8.2.2. 「$id」關鍵字

「$id」關鍵字使用其標準 URI 來識別架構資源。

請注意,此 URI 是識別符,不一定是網路定位器。對於可網路定址的 URL,架構不需要可從其標準 URI 下載。

如果存在,則此關鍵字的值必須是字串,並且必須表示有效的 URI 參考。此 URI 參考應正規化,並且必須解析為 絕對 URI(沒有片段)。因此,「$id」不得包含非空片段,並且不應包含空片段。

由於在 application/schema+json 媒體類型的上下文中,空片段指的是與沒有片段的基礎 URI 相同的資源,因此實作可以透過刪除片段來正規化以空片段結尾的 URI。但是,架構作者不應依賴不同實作的此行為。[CREF6]這主要是因為較舊的元架構在其 $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,如前一節所述之步驟所建立。

8.2.2.1. 識別根結構描述

JSON 結構描述文件的根結構描述應包含一個帶有絕對 URI(包含 scheme,但不包含 fragment)的「$id」關鍵字。

8.2.2.2. JSON 指標片段和嵌入式結構描述資源

由於 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 可能會降低結構描述的互通性。[CREF7]這是為了避免要求實作追蹤每個可能的基礎 URI 和 JSON 指標片段的整個堆疊,因為如果結構描述資源被重組,除了其中一個以外的所有內容都會變得脆弱。有人認為這很容易,因此沒有禁止它的必要,而另一些人則認為它會使結構描述識別複雜化,應該被禁止。我們鼓勵就此主題提供回饋。

此類非規範 URI 的更多範例以及應使用的適當規範 URI 在附錄 A 中提供。

8.2.3. 使用「$anchor」定義獨立於位置的識別符

使用 JSON 指標片段需要了解結構描述的結構。在編寫旨在提供可重複使用結構描述的結構描述文件時,最好使用未繫結至任何特定結構位置的純名稱片段。這允許重新定位子結構描述,而無需更新 JSON 指標參考。

「$anchor」關鍵字用於指定此類片段。它是一個識別符關鍵字,只能用於建立純名稱片段。

如果存在,此關鍵字的值必須是字串,且必須以字母 ([A-Za-z]) 開頭,後接任意數量的字母、數字 ([0-9])、連字號 ("-")、底線 ("_")、冒號 (":") 或句號 (".")。[CREF8]請注意,錨點字串不包含 "#" 字元,因為它不是 URI 參考。當在 URI 中使用時,「$anchor」:「foo」會變成片段「#foo」。請參閱下方完整範例。

附加產生的片段的基礎 URI 由上一節說明的「$id」關鍵字確定。如果兩個「$anchor」關鍵字套用於不同的基礎 URI,則它們在同一結構描述文件中可以具有相同的值,因為產生的完整 URI 將會不同。然而,兩個具有相同值和相同基礎 URI 的「$anchor」關鍵字的效果是未定義的。如果偵測到此類使用方式,實作可能會引發錯誤。

8.2.4. 結構描述參考

多個關鍵字可用於參考要套用於目前實例位置的結構描述。「$ref」和「$recursiveRef」是應用程式關鍵字,將參考的結構描述套用於實例。「$recursiveAnchor」是一個識別符關鍵字,用於控制如何確定用於解析「$recursiveRef」的 URI 參考值的基礎 URI。

由於「$ref」和「$recursiveRef」的值是 URI 參考,這允許將結構描述外部化或分割到多個檔案中,並提供透過自我參考來驗證遞迴結構的能力。

這些關鍵字產生的解析 URI 不一定是網路定位器,而只是一個識別符。如果結構描述是可網路定址的 URL,則不必從該位址下載,且實作不應假設它們在遇到可網路定址的 URI 時應執行網路操作。

8.2.4.1. 使用「$ref」的直接參考

「$ref」關鍵字是一個應用程式,用於參考靜態識別的結構描述。其結果是參考結構描述的結果。[CREF9]請注意,此關於如何確定結果的定義表示其他關鍵字可以與同一結構描述物件中的「$ref」同時出現。

「$ref」屬性的值必須是一個字串,該字串是一個 URI 參考。相對於目前的 URI 基礎解析,它會產生要套用的結構描述的 URI。

8.2.4.2. 使用「$recursiveRef」和「$recursiveAnchor」的遞迴參考

「$recursiveRef」和「$recursiveAnchor」關鍵字用於建構可延伸的遞迴結構描述。遞迴結構描述是指具有對其自身根目錄的參考的結構描述,該參考由空片段 URI 參考(「#」)識別。

簡單來說,「$recursiveRef」的行為與「$ref」完全相同,除非其目標結構描述包含值為 true 的「$recursiveAnchor」。在這種情況下,將檢查動態範圍以確定新的基礎 URI,並根據該基礎 URI 重新評估「$recursiveRef」中的 URI 參考。與使用「$id」變更基礎 URI 不同,使用「$recursiveAnchor」變更基礎 URI 是在每次解析「$recursiveRef」時計算的,並且不會影響任何其他關鍵字。

如需使用這些關鍵字的範例,請參閱附錄 C[CREF10]先前草案中的超結構描述中繼結構描述與此草案之間的差異,顯著展示了這些關鍵字的實用性。

8.2.4.2.1. 使用「$recursiveRef」的動態遞迴參考

「$recursiveRef」屬性的值必須是一個字串,該字串是一個 URI 參考。它是一個透過參考應用程式,使用動態計算的基礎 URI 來解析其值。

此關鍵字的行為僅針對值「#」定義。實作可能會選擇將其他值視為錯誤。[CREF11]此限制未來可能會放寬,但迄今為止只有值「#」具有明確的用例。

「$recursiveRef」的值最初是針對目前的基礎 URI 解析的,方式與「$ref」相同。

檢查由此產生的 URI 識別的結構描述是否存在「$recursiveAnchor」,並如以下章節中針對該關鍵字所述,計算新的基礎 URI。

最後,「$recursiveRef」的值會根據「$recursiveAnchor」確定的新基礎 URI 解析,產生最終解析的參考 URI。

請注意,在沒有「$recursiveAnchor」的情況下(以及在某些存在的情況下),「$recursiveRef」的行為與「$ref」的行為完全相同。

與「$ref」一樣,此關鍵字的結果是參考結構描述的結果。

8.2.4.2.2. 使用「$recursiveAnchor」啟用遞迴

「$recursiveAnchor」屬性的值必須為布林值。

「$recursiveAnchor」用於透過標記可以開始此類計算的位置和停止位置,在運行時動態識別「$recursiveRef」的基礎 URI。此關鍵字不得影響其他關鍵字的基礎 URI,除非它們被明確定義為依賴它。

如果設定為 true,則當包含結構描述物件被用作「$recursiveRef」的目標時,會透過檢查動態範圍來確定新的基礎 URI,以找出也包含值為 true 的「$recursiveAnchor」的最外層結構描述。該結構描述的基礎 URI 會被用作動態基礎 URI。

如果不存在此類結構描述,則基礎 URI 不會變更。

如果此關鍵字設定為 false,則基礎 URI 不會變更。

省略此關鍵字的行為與值為 false 的行為相同。

8.2.4.3. 防止無限遞迴

結構描述不得針對實例執行無限迴圈。例如,如果兩個結構描述「#alice」和「#bob」都具有參考對方的「allOf」屬性,則一個單純的驗證器可能會陷入無限遞迴迴圈,試圖驗證實例。結構描述不應使用此類無限遞迴巢狀結構;此行為是未定義的。

8.2.4.4. 參考可能的非結構描述

子結構描述物件(或布林值)可透過它們與已知應用程式關鍵字或與位置保留關鍵字(例如 「$defs」,該關鍵字採用一個或多個子結構描述作為值)的使用來識別。這些關鍵字可以是「$defs」和本文檔中的標準應用程式,或來自已知詞彙表的擴展關鍵字,或實作特定的自訂關鍵字。

未知關鍵字的多層結構能夠引入巢狀子結構描述,這些子結構描述將會受制於「$id」的處理規則。因此,在此類無法識別的結構中擁有參考目標無法可靠地實作,且產生的行為是未定義的。同樣地,已知關鍵字下方的參考目標(該關鍵字的值已知不是結構描述)會導致未定義的行為,以避免讓實作需要偵測此類目標。[CREF12]這些情境類似於透過 HTTP 擷取結構描述,但接收到的回應其 Content-Type 不是 application/schema+json。實作當然可以嘗試將其解釋為結構描述,但原始伺服器不保證它實際上是任何此類物件。因此,將其解釋為結構描述具有安全隱患,並可能產生不可預測的結果。

請注意,語法和語意與「$defs」相同的單層自訂關鍵字不允許任何介入的「$id」關鍵字,因此會在嘗試將任何參考目標用作結構描述的實作下正確運作。然而,此行為是實作特定的,且不得依賴它來實現互通性。

8.2.4.5. 載入參考的結構描述

使用 URI 來識別遠端結構描述並不一定意味著下載任何內容,而是 JSON 結構描述實作應提前了解它們將要使用的結構描述以及識別它們的 URI。

當下載 schema 時,例如由一個通用使用者代理程式下載,該程式在執行階段之前不知道要下載哪些 schema,請參閱超媒體的用法

實作應能將任意 URI 與任意 schema 關聯,和/或根據驗證器對 schema 的信任,自動關聯 schema 的 "$id" 所給定的 URI。這些 URI 和 schema 可以在處理實例之前提供給實作,或在處理 schema 文件時記錄在文件中,產生如附錄 A 所示的關聯。

一個 schema 可能(且很可能)有多個 URI,但一個 URI 無法識別多個 schema。當多個 schema 試圖識別為相同的 URI 時,驗證器應引發錯誤情況。

8.2.4.6. 取消參照

Schema 可以通過任何給定它們的 URI 來識別,包括 JSON 指標或它們由 "$id" 直接給定的 URI。在所有情況下,取消參照 "$ref" 參考涉及首先根據 RFC 3986 將其值解析為相對於當前基本 URI 的 URI 參考。

如果產生的 URI 識別出當前文件或已提供給實作的其他 schema 文件中的 schema,則應自動使用該 schema。

例如,考慮以下 schema

{
    "$id": "https://example.net/root.json",
    "items": {
        "type": "array",
        "items": { "$ref": "#item" }
    },
    "$defs": {
        "single": {
            "$anchor": "item",
            "type": "object",
            "additionalProperties": { "$ref": "other.json" }
        }
    }
}

                            

當實作遇到 <#/$defs/single> schema 時,它會將 "$id" URI 參考相對於當前基本 URI 解析,形成 <https://example.net/root.json#item>。

當實作然後查看 <#/items> schema 內部時,它會遇到 <#item> 參考,並將其解析為 <https://example.net/root.json#item>,它已在同一文件中看到定義,因此可以自動使用。

當實作遇到對 "other.json" 的參考時,它會將其解析為 <https://example.net/other.json>,這未在此文件中定義。如果具有該識別符的 schema 已以其他方式提供給實作,則也可以自動使用。[CREF13]當引用的 schema 未知時,實作應如何處理?是否允許自動網路取消參照的情況?同源政策?使用者可設定的選項?在超媒體 schema 所描述的不斷發展的 API 的情況下,預期新的 schema 將動態添加到系統中,因此對預先加載 schema 文件提出絕對要求是不可行的。

8.2.5. 使用 "$defs" 重新使用 Schema

"$defs" 關鍵字保留了一個位置,供 schema 作者將可重複使用的 JSON Schema 內聯到更通用的 schema 中。該關鍵字不會直接影響驗證結果。

此關鍵字的值必須是一個物件。此物件的每個成員值都必須是一個有效的 JSON Schema。

{
    "type": "array",
    "items": { "$ref": "#/$defs/positiveInteger" },
    "$defs": {
        "positiveInteger": {
            "type": "integer",
            "exclusiveMinimum": 0
        }
    }
}

                            

例如,以下是一個描述正整數陣列的 schema,其中正整數約束是 "$defs" 中的一個子 schema

8.3. 使用 "$comment" 進行註解

此關鍵字保留了一個位置,供 schema 作者向 schema 的讀者或維護者提供註解。

此關鍵字的值必須是字串。實作不得向最終使用者顯示此字串。用於編輯 schema 的工具應支援顯示和編輯此關鍵字。此關鍵字的值可用於針對正在使用 schema 的開發人員的除錯或錯誤輸出中。

Schema 詞彙表應允許在包含詞彙表關鍵字的任何物件中使用 "$comment"。實作可以假設允許使用 "$comment",除非詞彙表明確禁止。詞彙表不得指定 "$comment" 的任何效果超出本規範中所述的內容。

在應用程式/schema+json 之間轉換其他媒體類型或程式語言的工具,可以選擇將該媒體類型或程式語言的原生註解轉換為或從 "$comment" 值轉換。當原生註解和 "$comment" 屬性都存在時,此類轉換的行為取決於實作。

實作應將 "$comment" 視為與未知擴展關鍵字相同。它們可以在處理過程中的任何時間點移除 "$comment" 值。特別是,這允許在部署 schema 的大小是一個問題時縮短 schema。

實作不得基於 "$comment" 屬性的存在、不存在或內容採取任何其他動作。特別是,"$comment" 的值不得作為註解結果收集。

9. 應用子 schema 的詞彙表

本節定義了一個應用程式關鍵字的詞彙表,建議將其用作其他詞彙表的基礎。

不使用 "$vocabulary" 的元 schema 應被視為要求此詞彙表,就好像其 URI 的值為 true 一樣。

此詞彙表(稱為應用程式詞彙表)的當前 URI 為:<https://json-schema.dev.org.tw/draft/2019-09/vocab/applicator>

相應的元 schema 的當前 URI 為:<https://json-schema.dev.org.tw/draft/2019-09/meta/applicator>

更新的詞彙表和元架構 URI 可以在規格草案之間發布,以更正錯誤。實作應考慮在本規格草案之後和下一個規格草案之前註明日期的 URI,以表示與此處列出的語法和語意相同。

9.1. 關鍵字的獨立性

Schema 關鍵字通常獨立運作,不會影響彼此的結果。

為了方便 schema 作者,此詞彙表中的關鍵字有一些例外

9.2. 在原地應用子 schema 的關鍵字

這些關鍵字將子 schema 應用於實例中與父 schema 應用於同一位置。它們允許以各種方式組合或修改子 schema 結果。

9.2.1. 使用布林邏輯應用子 schema 的關鍵字

這些關鍵字對應於用於組合或修改子 schema 的布林斷言結果的邏輯運算子。它們對註解收集沒有直接影響,儘管它們使相同的註解關鍵字能夠以不同的值應用於實例位置。註解關鍵字定義了它們自己的規則來組合這些值。

9.2.1.1. allOf

此關鍵字的值必須是非空陣列。陣列的每個項目都必須是有效的 JSON Schema。

如果實例成功地針對此關鍵字的值所定義的所有 schema 進行驗證,則該實例會成功地針對此關鍵字進行驗證。

9.2.1.2. anyOf

此關鍵字的值必須是非空陣列。陣列的每個項目都必須是有效的 JSON Schema。

如果實例成功地針對此關鍵字的值所定義的至少一個 schema 進行驗證,則該實例會成功地針對此關鍵字進行驗證。請注意,當收集註解時,必須檢查所有子 schema,以便從每個成功驗證的子 schema 收集註解。

9.2.1.3. oneOf

此關鍵字的值必須是非空陣列。陣列的每個項目都必須是有效的 JSON Schema。

如果實例成功地針對此關鍵字的值所定義的恰好一個 schema 進行驗證,則該實例會成功地針對此關鍵字進行驗證。

9.2.1.4. not

此關鍵字的值必須是有效的 JSON Schema。

如果實例未能成功地針對此關鍵字定義的 schema 進行驗證,則該實例對此關鍵字有效。

9.2.2. 有條件地應用子 schema 的關鍵字

這些關鍵字中的三個協同工作,以根據另一個子 schema 的結果來實現子 schema 的條件應用。第四個是特定條件情況的捷徑。

"if"、"then" 和 "else" 不得在子 schema 邊界之間相互作用。換句話說,"allOf" 的一個分支中的 "if" 不得對另一個分支中的 "then" 或 "else" 產生影響。

當 "if"、"then" 或 "else" 不存在時,沒有預設行為。特別是,它們不得被視為存在一個空的 schema,並且當 "if" 不存在時,"then" 和 "else" 都必須完全忽略。

9.2.2.1. if

此關鍵字的值必須是有效的 JSON Schema。

此關鍵字的子 schema 的驗證結果對整體驗證結果沒有直接影響。相反,它控制評估 "then" 或 "else" 關鍵字中的哪一個。

成功針對此關鍵字的子 schema 進行驗證的實例,如果存在,也必須對 "then" 關鍵字的子 schema 值有效。

未能針對此關鍵字的子 schema 進行驗證的實例,如果存在,也必須對 "else" 關鍵字的子 schema 值有效。

如果正在收集 註解,則以通常的方式從此關鍵字的子 schema 收集它們,包括當關鍵字存在而沒有 "then" 或 "else" 時。

9.2.2.2. then

此關鍵字的值必須是有效的 JSON Schema。

當 "if" 存在,且實例成功地針對其子 schema 進行驗證時,如果實例也成功地針對此關鍵字的子 schema 進行驗證,則對此關鍵字的驗證成功。

當 "if" 不存在時,或當實例未能針對其子 schema 進行驗證時,此關鍵字沒有作用。在這種情況下,實作不得為了驗證或註解收集目的而針對此關鍵字評估實例。

9.2.2.3. else

此關鍵字的值必須是有效的 JSON Schema。

當 "if" 存在,且實例未能針對其子 schema 進行驗證時,如果實例成功地針對此關鍵字的子 schema 進行驗證,則對此關鍵字的驗證成功。

當 "if" 不存在時,或當實例成功地針對其子 schema 進行驗證時,此關鍵字沒有作用。在這種情況下,實作不得為了驗證或註解收集目的而針對此關鍵字評估實例。

9.2.2.4. dependentSchemas

此關鍵字指定如果實例是物件且包含某個屬性,則會評估的子 schema。

此關鍵字的值必須是一個物件。物件中的每個值都必須是有效的 JSON Schema。

如果物件鍵是實例中的屬性,則整個實例必須針對子 schema 進行驗證。它的使用取決於屬性的存在。

省略此關鍵字的行為與空物件相同。

9.3. 將子 schema 應用於子實例的關鍵字

每個關鍵字都定義了一個規則,用於將其子 schema 應用於子實例,特別是物件屬性和陣列項目,並組合它們的結果。

9.3.1. 將子 schema 應用於陣列的關鍵字

9.3.1.1. items

"items" 的值必須是有效的 JSON Schema 或有效的 JSON Schema 陣列。

如果 "items" 是一個 schema,則如果陣列中的所有元素都成功地針對該 schema 進行驗證,則驗證成功。

如果 "items" 是一個 schema 陣列,則如果實例的每個元素都針對相同位置的 schema(如果存在)進行驗證,則驗證成功。

此關鍵字產生一個註解值,該值是此關鍵字應用子 schema 的最大索引。如果將子 schema 應用於實例的每個索引,例如當 "items" 是一個 schema 時,該值可能是布林值 true。

如果任何值為 true,則通過將組合結果設置為 true 來組合應用於同一實例位置的多個 schema 的 "items" 關鍵字的註解結果,否則保留最大的數值。

省略此關鍵字的斷言行為與空 schema 相同。

9.3.1.2. additionalItems

"additionalItems" 的值必須是有效的 JSON Schema。

此關鍵字的行為取決於同一個綱要物件內是否存在「items」及其註解結果。如果存在「items」,且其註解結果為數字,則當索引大於該數字的每個實例元素都通過「additionalItems」的驗證時,驗證成功。

否則,如果「items」不存在或其註解結果為布林值 true,「additionalItems」必須被忽略。

如果「additionalItems」子綱要應用於實例陣列中的任何位置,則會產生布林值 true 的註解結果,類似於「items」的單一綱要行為。如果從應用於同一個實例位置的任何子綱要中,任何「additionalItems」關鍵字產生了 true 的註解值,則這些關鍵字的組合結果也為 true。

省略此關鍵字的斷言行為與空 schema 相同。

實作可以選擇以其他方式實作或最佳化此關鍵字,以產生相同的效果,例如直接檢查「items」陣列是否存在及其大小。不支援收集註解的實作必須這樣做。

9.3.1.3. unevaluatedItems

「unevaluatedItems」的值必須是有效的 JSON 綱要。

此關鍵字的行為取決於應用於正在驗證的實例位置的相鄰關鍵字的註解結果。具體而言,來自「items」和「additionalItems」的註解,當它們與「unevaluatedItems」關鍵字相鄰時,可能會來自這些關鍵字。這兩個註解以及「unevaluatedItems」也可能來自任何和所有相鄰的原地應用器關鍵字。這包括但不限於本文檔中定義的原地應用器。

如果存在「items」註解,且其註解結果為數字,且不存在「additionalItems」或「unevaluatedItems」註解,則當索引大於「items」註解的每個實例元素都通過「unevaluatedItems」的驗證時,驗證成功。

否則,如果存在任何值為布林值 true 的「items」、「additionalItems」或「unevaluatedItems」註解,則必須忽略「unevaluatedItems」。但是,如果不存在這些註解,則必須將「unevaluatedItems」應用於陣列中的所有位置。

這表示必須先評估「items」、「additionalItems」和所有原地應用器,才能評估此關鍵字。擴充關鍵字的作者不得定義需要在評估此關鍵字之前評估的原地應用器。

如果「unevaluatedItems」子綱要應用於實例陣列中的任何位置,則會產生布林值 true 的註解結果,類似於「items」的單一綱要行為。如果從應用於同一個實例位置的任何子綱要中,任何「unevaluatedItems」關鍵字產生了 true 的註解值,則這些關鍵字的組合結果也為 true。

省略此關鍵字的斷言行為與空 schema 相同。

不收集註解的實作在遇到此關鍵字時必須引發錯誤。

9.3.1.4. contains

此關鍵字的值必須是有效的 JSON 綱要。

如果陣列實例的至少一個元素通過給定綱要的驗證,則該陣列實例通過「contains」的驗證。請注意,當收集註解時,即使在找到第一個匹配項之後,也必須將子綱要應用於每個陣列元素。這是為了確保收集所有可能的註解。

9.3.2. 將子綱要應用於物件的關鍵字

9.3.2.1. properties

「properties」的值必須是一個物件。此物件的每個值都必須是有效的 JSON 綱要。

如果對於實例中和此關鍵字的值中都出現的每個名稱,該名稱的子實例成功通過對應綱要的驗證,則驗證成功。

此關鍵字的註解結果是此關鍵字匹配的實例屬性名稱的集合。應用於同一個實例位置的多個綱要中的「properties」關鍵字的註解結果,會透過取集合的聯集來組合。

省略此關鍵字與空物件具有相同的斷言行為。

9.3.2.2. patternProperties

「patternProperties」的值必須是一個物件。此物件的每個屬性名稱都應是有效的正規表示式,根據 ECMA 262 正規表示式方言。此物件的每個屬性值都必須是有效的 JSON 綱要。

如果對於與此關鍵字的值中作為屬性名稱出現的任何正規表示式匹配的每個實例名稱,該名稱的子實例成功通過與匹配的正規表示式對應的每個綱要的驗證,則驗證成功。

此關鍵字的註解結果是此關鍵字匹配的實例屬性名稱的集合。應用於同一個實例位置的多個綱要中的「patternProperties」關鍵字的註解結果,會透過取集合的聯集來組合。

省略此關鍵字與空物件具有相同的斷言行為。

9.3.2.3. additionalProperties

「additionalProperties」的值必須是有效的 JSON 綱要。

此關鍵字的行為取決於同一個綱要物件內是否存在「properties」和「patternProperties」及其註解結果。「additionalProperties」的驗證僅適用於未出現在「properties」或「patternProperties」的註解結果中的實例名稱的子值。

對於所有此類屬性,如果子實例通過「additionalProperties」綱要的驗證,則驗證成功。

此關鍵字的註解結果是此關鍵字的子綱要驗證的實例屬性名稱的集合。應用於同一個實例位置的多個綱要中的「additionalProperties」關鍵字的註解結果,會透過取集合的聯集來組合。

省略此關鍵字的斷言行為與空 schema 相同。

實作可以選擇以其他方式實作或最佳化此關鍵字,以產生相同的效果,例如直接根據實例屬性集檢查「properties」中的名稱和「patternProperties」中的模式。不支援收集註解的實作必須這樣做。

9.3.2.4. unevaluatedProperties

「unevaluatedProperties」的值必須是有效的 JSON 綱要。

此關鍵字的行為取決於應用於正在驗證的實例位置的相鄰關鍵字的註解結果。具體而言,來自「properties」、「patternProperties」和「additionalProperties」的註解,當它們與「unevaluatedProperties」關鍵字相鄰時,可能會來自這些關鍵字。這三個註解以及「unevaluatedProperties」也可能來自任何和所有相鄰的原地應用器關鍵字。這包括但不限於本文檔中定義的原地應用器。

「unevaluatedProperties」的驗證僅適用於未出現在應用於正在驗證的實例位置的「properties」、「patternProperties」、「additionalProperties」或「unevaluatedProperties」註解結果中的實例名稱的子值。

對於所有此類屬性,如果子實例通過「unevaluatedProperties」綱要的驗證,則驗證成功。

這表示必須先評估「properties」、「patternProperties」、「additionalProperties」和所有原地應用器,才能評估此關鍵字。擴充關鍵字的作者不得定義需要在評估此關鍵字之前評估的原地應用器。

此關鍵字的註解結果是此關鍵字的子綱要驗證的實例屬性名稱的集合。應用於同一個實例位置的多個綱要中的「unevaluatedProperties」關鍵字的註解結果,會透過取集合的聯集來組合。

省略此關鍵字的斷言行為與空 schema 相同。

不收集註解的實作在遇到此關鍵字時必須引發錯誤。

9.3.2.5. propertyNames

「propertyNames」的值必須是有效的 JSON 綱要。

如果實例是一個物件,則當實例中的每個屬性名稱都通過提供的綱要驗證時,此關鍵字會通過驗證。請注意,綱要正在測試的屬性名稱將始終是一個字串。

省略此關鍵字與空綱要具有相同的行為。

10. 輸出格式化

JSON 綱要被定義為與平台無關。因此,為了提高跨平台的相容性,實作應符合標準的驗證輸出格式。本節介紹消費者需要正確解讀驗證結果的最低要求。

10.1. 格式

JSON 綱要輸出是使用第 4.2.1 節中描述的 JSON 綱要資料實例模型定義的。實作可以偏離此規範,並由其特定的語言和平台支援,但是建議透過序列化或其他方式,將輸出轉換為本文定義的 JSON 格式。

10.2. 輸出格式

本規範定義了四種輸出格式。請參閱「輸出結構」部分,以了解每種格式的要求。

實作應至少提供「旗標」、「基本」或「詳細」格式,並且可以提供「詳細」格式。如果提供了一種或多種複雜格式,則還必須提供「旗標」格式。實作應在其文件中指定它們支援的格式。

10.3. 最低限度的資訊

除了簡單的「旗標」輸出外,其他資訊對於協助除錯綱要或實例很有用。每個子結果應至少包含本節中包含的資訊。

包含所有這些元件的單一物件被視為一個輸出單元。

實作可以選擇提供其他資訊。

10.3.1. 關鍵字的相對位置

遵循驗證路徑的驗證關鍵字的相對位置。該值必須表示為 JSON 指標,並且必須包括任何依參照應用器,例如「$ref」或「$recursiveRef」。

#/properties/width/$ref/minimum

                        

請注意,由於包含這些依參照應用器關鍵字,此指標可能無法通過正常的 JSON 指標過程解析。

此資訊的 JSON 鍵是「keywordLocation」。

10.3.2. 關鍵字的絕對位置

驗證關鍵字的絕對、取消參照位置。該值必須使用相關綱要物件的正規 URI 表示為絕對 URI,並且不得包含依參照應用器,例如「$ref」或「$recursiveRef」作為非終端路徑元件。如果錯誤或註解是針對該關鍵字(例如無法解析的參照),則可以以此類關鍵字結尾。

https://example.com/schemas/common#/$defs/count/minimum

                        

僅當相對位置不包含任何參照,或者綱要未將絕對 URI 宣告為其「$id」時,才能省略此資訊。

此資訊的 JSON 鍵是「absoluteKeywordLocation」。

10.3.3. 實例位置

正在驗證的實例中 JSON 值的位置。該值必須表示為 URI 片段編碼的 JSON 指標。

此資訊的 JSON 鍵是「instanceLocation」。

10.3.4. 錯誤或註解

驗證產生的錯誤或註解。

對於錯誤,此規範未定義訊息的特定措辭。實作將需要提供此資訊。

對於註解,每個產生註解的關鍵字都會指定其格式。預設情況下,它是關鍵字的值。

失敗驗證的 JSON 鍵是「error」;成功驗證的 JSON 鍵是「annotation」。

10.3.5. 巢狀結果

對於兩個階層式結構,此屬性將保存巢狀錯誤和註解。

在驗證失敗的情況下,巢狀結果的 JSON 鍵為 "errors";在驗證成功的情況下,則為 "annotations"。請注意複數形式,因為帶有巢狀結果的關鍵字也可能具有局部錯誤或註解。

10.4. 輸出結構

輸出必須是一個物件,其中包含一個名為 "valid" 的布林值屬性。當需要關於結果的額外資訊時,輸出也必須包含 "errors" 或 "annotations",如下所述。

在這些範例中,將使用以下綱要和實例。

{
  "$id": "https://example.com/polygon",
  "$schema": "https://json-schema.dev.org.tw/draft/2019-09/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
  }
]

                    

此實例將驗證失敗並產生錯誤,但推導出產生註解的通過綱要範例是微不足道的。

具體來說,它將產生的錯誤是

請注意,這些範例中描述的錯誤訊息措辭並非本規範的要求。實作應根據其受眾調整錯誤訊息,或提供範本機制,讓使用者可以製作自己的訊息。

10.4.1. 旗標

在最簡單的情況下,只需滿足 "valid" 屬性的布林值結果即可。

{
  "valid": false
}

                        

由於此格式不返回錯誤或註解,因此建議實作使用短路邏輯,在可以確定結果時立即返回失敗或成功。例如,如果 "anyOf" 關鍵字包含五個子綱要,且第二個子綱要通過,則無需檢查其他三個。該邏輯可以簡單地返回成功。

10.4.2. 基本

"基本" 結構是一個平面輸出單元列表。

{
  "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"
    }
  ]
}

                        

10.4.3. 詳細

"詳細" 結構基於綱要,對人類和機器而言都更易於閱讀。以這種方式組織結構可以使錯誤之間的關聯更加明顯。例如,缺少 "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"
    }
  ]
}

                        

10.4.4. 冗長

"冗長" 結構是一個完全實現的階層結構,與綱要的階層結構完全匹配。此結構在表單產生和驗證中具有應用,其中錯誤的位置很重要。

此結構與 "詳細" 結構的主要差異在於會返回所有結果。這包括本來會被移除的子綱要驗證結果(例如,失敗驗證的註解,`not` 關鍵字內成功的驗證等)。因此,建議每個節點也攜帶一個 `valid` 屬性,以指示該節點的驗證結果。

由於此輸出結構可能非常大,因此為了簡潔起見,此處提供一個較小的範例。上述範例的完整輸出結構的 URI 為:<https://json-schema.dev.org.tw/draft/2019-09/output/verbose-example>

// schema
{
  "$id": "https://example.com/polygon",
  "$schema": "https://json-schema.dev.org.tw/draft/2019-09/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."
        }
      ]
    }
  ]
}

                        

10.4.5. 輸出驗證綱要

為方便起見,已提供 JSON 綱要來驗證實作產生的輸出。其 URI 為:<https://json-schema.dev.org.tw/draft/2019-09/output/schema>

11. 用於超媒體

JSON 已被 HTTP 伺服器廣泛採用,用於自動化 API 和機器人。本節描述在使用支援媒體類型和 Web 連結的協定時,如何以更符合 RESTful 的方式加強 JSON 文件處理。

11.1. 連結至綱要

建議由綱要描述的實例使用連結關係 "describedby" 提供一個連結至可下載的 JSON 綱要,如 連結資料協定 1.0,第 8.1 節中所定義。

在 HTTP 中,可以使用 Link 標頭將此類連結附加至任何回應。此類標頭的範例將是

Link: <https://example.com/my-hyper-schema#>; rel="describedby"

                    

11.2. 透過媒體類型參數識別綱要

媒體類型可以允許 "schema" 媒體類型參數,這使 HTTP 伺服器能夠根據綱要執行 Content-Type Negotiation。媒體類型參數必須是以空格分隔的 URI 列表(即相對引用無效)。

使用媒體類型 application/schema-instance+json 時,必須提供 "schema" 參數。

使用媒體類型 application/schema+json 時,可以提供 "schema" 參數。如果提供,它應包含與 "$schema" 關鍵字識別的 URI 相同的 URI,並且可以包含其他 URI。無論是否有其他替代或額外的中繼綱要作為媒體類型參數,"$schema" URI 都必須被視為綱要的標準中繼綱要。

綱要 URI 是不透明的,不應自動取消引用。如果實作不理解提供的綱要的語意,實作可以改為遵循 "describedby" 連結(如果有的話),這可能會提供關於如何處理綱要的資訊。由於 "schema" 不一定指向網路位置,因此 "describedby" 關係用於連結至可下載的綱要。但是,為簡單起見,綱要作者應在可能的情況下使這些 URI 指向相同的資源。

在 HTTP 中,媒體類型參數將在 Content-Type 標頭中發送

Content-Type: application/json;
          schema="https://example.com/my-hyper-schema#"

                    

多個綱要以空格分隔,並表示該實例符合所有列出的綱要

Content-Type: application/json;
          schema="https://example.com/alice https://example.com/bob"

                    

媒體類型參數也用於 HTTP 的 Accept 請求標頭中

Accept: application/json;
          schema="https://example.com/qiang https://example.com/li",
        application/json;
          schema="https://example.com/kumar"

                    

與 Content-Type 一樣,同一字串中的多個綱要參數會請求符合所有列出綱要的實例。

與 Content-Type 不同,Accept 可以包含多個值,以指示客戶端可以接受多種媒體類型。在上面的範例中,請注意,這兩種媒體類型僅在其綱要參數值上有所不同。這會請求符合至少一個識別綱要的 application/json 表示法。

[CREF14]此段落假設我們可以註冊 "schema" 連結關係。我們現在是否應改為指定類似 "tag:json-schema.org,2017:schema" 的內容? HTTP 也可以在連結中發送 "schema",儘管如果這完全取代了媒體類型參數,可能會影響媒體類型語意和 Content-Type Negotiation

Link: </alice>;rel="schema", </bob>;rel="schema"

                    

11.3. 在 HTTP 上使用

當用於網路上的超媒體系統時,HTTP 通常是用於分發綱要的首選協定。如果錯誤行為的客戶端比必要時更頻繁地從網路提取綱要(而實際上可以長時間快取綱要),則可能會對伺服器維護人員造成問題。

HTTP 伺服器應在 JSON 綱要上設定長期快取標頭。HTTP 客戶端應觀察快取標頭,並且不在其新鮮度期間內重新請求文件。分散式系統應使用共用快取和/或快取 Proxy。

User-Agent: product-name/5.4.1 so-cool-json-schema/1.0.2 curl/7.43.0

                        

客戶端應設定或附加特定於 JSON 綱要實作或軟體產品的 User-Agent 標頭。由於符號按重要性遞減的順序列出,因此 JSON 綱要程式庫名稱/版本應位於較通用的 HTTP 程式庫名稱(如果有的話)之前。例如

客戶端應能夠使用 "From" 標頭提出請求,以便伺服器運營商可以聯繫可能行為不當的腳本的所有者。

12. 安全性考量

綱要和實例都是 JSON 值。因此,RFC 8259 中定義的所有安全性考量都適用。

實例和綱要通常都是由不受信任的第三方編寫,部署在公共網際網路伺服器上。驗證器應注意,針對綱要的剖析和驗證不會消耗過多的系統資源。驗證器不得陷入無限迴圈。

伺服器必須確保惡意方無法透過上傳具有預先存在的或非常相似的 "$id" 的綱要來變更現有綱要的功能。

個別的 JSON 綱要詞彙也可能會有自己的安全性考量。有關詳細資訊,請參閱各自的規範。

綱要作者應注意 "$comment" 內容,因為惡意實作可能會違反規範,將其顯示給終端使用者,或者在預期此行為時未能剝離它們。

惡意綱要作者可能會在 "$comment" 中放入可執行程式碼或其他危險資料。實作不得根據 "$comment" 內容剖析或採取其他動作。

13. IANA 考量

13.1. application/schema+json

JSON 綱要的擬議 MIME 媒體類型定義如下

13.2. application/schema-instance+json

JSON 綱要實例的擬議 MIME 媒體類型(需要特定於 JSON 綱要的媒體類型)定義如下

14. 參考

14.1. 標準參考

[ecma262] "ECMA 262 規格"
[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 月。

14.2. 參考資料 (提供資訊)

[json-hyper-schema] Andrews, H.A. Wright, "JSON 超級綱要:JSON 超媒體註解的詞彙", Internet-Draft draft-handrews-json-schema-hyperschema-02, 2017 年 11 月。
[json-schema-validation] Wright, A.Andrews, H.G. Luff, "JSON 綱要驗證:JSON 結構驗證的詞彙", Internet-Draft draft-handrews-json-schema-validation-02, 2017 年 11 月。
[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 月。

附錄 A. 綱要識別範例

考量以下綱要,其中顯示 "$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"
        }
    }
}

                

根據上面第 5 節和 8.2.2.2 節,以下 URI 編碼 JSON 指標(相對於根綱要)中的綱要具有以下基礎 URI,並且可由任何列出的 URI 識別。

# (文件根)
標準絕對 URI(也是基礎 URI)
https://example.com/root.json
具有指標片段的標準 URI
https://example.com/root.json#

#/$defs/A
基礎 URI
https://example.com/root.json
具有純片段的標準 URI
https://example.com/root.json#foo
具有指標片段的標準 URI
https://example.com/root.json#/$defs/A

#/$defs/B
基礎 URI
https://example.com/other.json
具有指標片段的標準 URI
https://example.com/other.json#
相對於 root.json 的非標準 URI 與片段
https://example.com/root.json#/$defs/B

#/$defs/B/$defs/X
基礎 URI
https://example.com/other.json
具有純片段的標準 URI
https://example.com/other.json#bar
具有指標片段的標準 URI
https://example.com/other.json#/$defs/X
相對於 root.json 的非標準 URI 與片段
https://example.com/root.json#/$defs/B/$defs/X

#/$defs/B/$defs/Y
基礎 URI
https://example.com/t/inner.json
具有純片段的標準 URI
https://example.com/t/inner.json#bar
具有指標片段的標準 URI
https://example.com/t/inner.json#
相對於 other.json 的非標準 URI 與片段
https://example.com/other.json#/$defs/Y
相對於 root.json 的非標準 URI 與片段
https://example.com/root.json#/$defs/B/$defs/Y

#/$defs/C
基礎 URI
urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f
具有指標片段的標準 URI
urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f#
相對於 root.json 的非標準 URI 與片段
https://example.com/root.json#/$defs/C

附錄 B. 操作綱要文件和參考

已建立各種工具,根據參考 ("$ref") 出現的方式和位置來重新排列綱要文件。本附錄討論哪些使用案例和動作符合此規格。

B.1. 將綱要資源捆綁到單一文件中

一組預期一起使用的綱要資源可以組織在各自的綱要文件中,全部在同一個綱要文件中,或介於兩者之間的任何文件分組粒度。

存在許多工具可以執行各種參考移除。其中一個常見的案例是產生一個單一檔案,其中所有參考都可以在該檔案中解析。這通常是為了簡化分發,或簡化程式碼編寫,以便 JSON 綱要程式庫的各種調用不必追蹤和載入大量資源。

只要所有靜態參考 (例如 "$ref") 使用解析為標準 URI 的 URI 參考,並且所有綱要資源在其根綱要中具有絕對 URI 作為 "$id",就可以安全且可逆地完成此轉換。

滿足這些條件後,每個外部資源都可以複製到 "$defs" 下,而不會破壞資源綱要物件之間的任何參考,也不會變更驗證或註解結果的任何方面。"$defs" 下綱要的名稱不會影響行為,假設它們各自是唯一的,因為它們不會出現在嵌入資源的標準 URI 中。

B.2. 參考移除並非總是安全的

嘗試移除所有參考並產生單一綱要文件並非在所有情況下都會產生與原始形式具有相同行為的綱要。

由於 "$ref" 現在被視為任何其他關鍵字,允許在同一個綱要物件中使用其他關鍵字,因此在所有情況下完全支援非遞迴的 "$ref" 移除可能需要相對複雜的綱要操作。判斷或提供一組安全的 "$ref" 移除轉換並不在本規格的範圍內,因為它們不僅取決於綱要結構,也取決於預期的用途。

附錄 C. 遞迴綱要擴充範例

考量以下兩個綱要,描述一個簡單的遞迴樹狀結構,其中樹狀結構中的每個節點都可以具有任何類型的「資料」欄位。第一個綱要允許並忽略其他實例屬性。第二個綱要更嚴格,僅允許「資料」和「子系」屬性。也顯示了一個「資料」拼寫錯誤為「daat」的範例實例。

// tree schema, extensible
{
    "$schema": "https://json-schema.dev.org.tw/draft/2019-09/schema",
    "$id": "https://example.com/tree",
    "$recursiveAnchor": true,

    "type": "object",
    "properties": {
        "data": true,
        "children": {
            "type": "array",
            "items": {
                "$recursiveRef": "#"
            }
        }
    }
}

// strict-tree schema, guards against misspelled properties
{
    "$schema": "https://json-schema.dev.org.tw/draft/2019-09/schema",
    "$id": "https://example.com/strict-tree",
    "$recursiveAnchor": true,

    "$ref": "tree",
    "unevaluatedProperties": false
}

// instance with misspelled field
{
    "children": [ { "daat": 1 } ]
}

                

如果我們將「strict-tree」綱要套用至實例,我們將遵循 "$ref" 到「tree」綱要,檢查其「子系」子綱要,並在其「項目」子綱要中找到 "$recursiveAnchor"。此時,動態路徑為 "#/$ref/properties/children/items/$recursiveRef"。

此時的基礎 URI 為 "https://example.com/tree",因此 "$recursiveRef" 最初解析為 "https://example.com/tree#"。由於 "$recursiveAnchor" 為 true,因此我們檢查動態路徑,以查看是否有不同的基礎 URI 要使用。我們在 "#" 和 "#/$ref" 的動態路徑中找到一個具有 true 值的 "$recursiveAnchor"。

最外層為 "#",它是「strict-tree」綱要的根綱要,因此我們使用其 "https://example.com/strict-tree" 的基礎 URI,它會產生 "$recursiveRef" 的最終解析 URI "https://example.com/strict-tree#"。

如此一來,「tree」綱要中的遞迴會遞迴到「strict-tree」的根,而不是僅將「strict-tree」套用至實例根,而是將「tree」套用至實例子系。

附錄 D. 使用詞彙表

D.1. 詞彙表和中繼綱要作者的最佳實務

如果詞彙表預期廣泛使用,並可能與其他詞彙表結合使用,詞彙表作者應注意避免關鍵字名稱衝突。JSON 綱要未提供任何正式的命名空間系統,但也不會限制關鍵字名稱,允許使用任何數量的命名空間方法。

詞彙表可以互相建構,例如透過定義其關鍵字相對於另一個詞彙表的關鍵字的行為,或透過使用另一個詞彙表的關鍵字並限制或擴展一組可接受的值。並非所有此類詞彙表重新使用都會產生與其建構所依據的詞彙表相容的新詞彙表。詞彙表作者應清楚記錄預期的相容性層級 (如果有的話)。

中繼綱要作者不應使用 "$vocabulary" 來組合為同一個關鍵字定義衝突語法或語義的多個詞彙表。由於語義衝突通常無法透過綱要驗證來偵測,因此預期實作不會偵測到此類衝突。如果宣告了衝突的詞彙表,則產生的行為是未定義的。

詞彙表作者應提供一個中繼綱要,用於驗證詞彙表關鍵字本身的預期使用方式。此類中繼綱要不應禁止其他關鍵字,且不得禁止任何來自核心詞彙表的關鍵字。

建議中繼綱要作者使用 "allOf" 關鍵字來參考每個詞彙表的中繼綱要,儘管其他建構中繼綱要的機制可能適用於某些使用案例。

中繼綱要的遞迴性質使得 "$recursiveAnchor" 和 "$recursiveRef" 關鍵字特別適用於擴充現有的中繼綱要,這可以從擴充驗證中繼綱要的 JSON 超級綱要中繼綱要中看出。

除了宣告的詞彙表所描述的內容之外,中繼綱要可能會施加其他限制,包括描述任何詞彙表中不存在的關鍵字。這允許將使用限制在詞彙表的子集中,並驗證不適用於重新使用的本機定義的關鍵字。

然而,中繼綱要不應與其宣告的任何詞彙表相矛盾,例如要求與詞彙表預期的 JSON 類型不同的類型。產生的行為是未定義的。

對於在本機使用且不需要在任意實作中測試詞彙表支援的中繼綱要,可以安全地完全省略 "$vocabulary"。

D.2. 具有詞彙表宣告的範例中繼綱要

此中繼綱要明確宣告核心詞彙表和應用程式詞彙表,以及擴充詞彙表,並使用 "allOf" 組合它們的中繼綱要。擴充詞彙表的中繼綱要(僅描述該詞彙表中的關鍵字)顯示在主要範例中繼綱要之後。

主要範例中繼綱要也透過禁止以 "unevaluated" 為字首的關鍵字來限制應用程式詞彙表的使用,這些關鍵字特別難以實作。這不會變更應用程式詞彙表所定義的語義或關鍵字集。它僅確保使用此中繼綱要嘗試使用以 "unevaluted" 為字首的關鍵字的綱要,將無法通過此中繼綱要的驗證。

最後,此中繼綱要描述了一個關鍵字 "localKeyword" 的語法,該關鍵字不屬於任何詞彙表。據推測,此中繼綱要的實作人員和使用者將了解 "localKeyword" 的語義。JSON 綱要未定義任何在詞彙表之外表達關鍵字語義的機制,使得它們不適合在理解它們的特定環境之外使用。

此中繼綱要組合了多個詞彙表,以供一般使用。

{
  "$schema": "https://json-schema.dev.org.tw/draft/2019-09/schema",
  "$id": "https://example.com/meta/general-use-example",
  "$recursiveAnchor": true,
  "$vocabulary": {
    "https://json-schema.dev.org.tw/draft/2019-09/vocab/core": true,
    "https://json-schema.dev.org.tw/draft/2019-09/vocab/applicator": true,
    "https://json-schema.dev.org.tw/draft/2019-09/vocab/validation": true,
    "https://example.com/vocab/example-vocab": true
  },
  "allOf": [
    {"$ref": "https://json-schema.dev.org.tw/draft/2019-09/meta/core"},
    {"$ref": "https://json-schema.dev.org.tw/draft/2019-09/meta/applicator"},
    {"$ref": "https://json-schema.dev.org.tw/draft/2019-09/meta/validation"},
    {"$ref": "https://example.com/meta/example-vocab",
  ],
  "patternProperties": {
    "^unevaluated.*$": false
  },
  "properties": {
    "localKeyword": {
      "$comment": "Not in vocabulary, but validated if used",
      "type": "string"
    }
  }
}

                    

此中繼綱要僅描述一個單一擴充詞彙表。

{
  "$schema": "https://json-schema.dev.org.tw/draft/2019-09/schema",
  "$id": "https://example.com/meta/example-vocab",
  "$recursiveAnchor": true,
  "$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",
    }
  }
}

                    

如上所示,即使一般使用中繼綱要的 "allOf" 中引用的每個單一詞彙表中繼綱要都宣告其對應的詞彙表,此新的中繼綱要也必須重新宣告它們。

組合核心和驗證規格所定義的所有詞彙表的標準中繼綱要,以及組合這些規格以及超級綱要規格所定義的所有詞彙表的標準中繼綱要,展示了其他複雜的組合。這些中繼綱要的 URI 可以在驗證和超級綱要規格中找到。

雖然一般用途的中繼綱要可以驗證 "minDate" 的語法,但詞彙表定義了 "minDate" 的語義含義背後的邏輯。如果不了解語義 (在此範例中,實例值必須是等於或晚於綱要中提供的關鍵字值的日期),實作只能驗證語法使用方式。在這種情況下,這表示驗證它是否為日期格式的字串 (使用 "pattern" 以確保即使 "format" 純粹作為註解時也進行驗證,如 驗證規格 中所述)。

附錄 E. 參考和生成使用案例

雖然預期參考的存在對於驗證結果是透明的,但程式碼產生器和 UI 渲染器等生成使用案例通常會認為參考在語義上很重要。

為了明確表達這種特定使用情境的語義,最佳實務是在同一個 schema 物件中,與 "$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",
        }
    }
}

                

在此,這個 schema 代表某種類型的物件導向類別。 "allOf" 中的第一個參考被標示為基底類別。第二個則未被賦予類別關係,這意味著程式碼產生器應該將目標的定義與這個定義組合在一起,就像沒有涉及參考一樣。

查看屬性,「foo」被標記為物件組合,而「date」屬性則沒有。它只是一個具有子欄位的欄位,而不是一個獨立類別的實例。

這種使用方式要求註解必須與參考位於同一個物件中,而且該參考必須是可識別的參考。

附錄 F. 致謝

感謝 Gary Court、Francis Galiegue、Kris Zyp 和 Geraint Luff 對 JSON Schema 初稿的貢獻。

感謝 Jason Desrosiers、Daniel Perrett、Erik Wilde、Ben Hutton、Evgeny Poberezkin、Brad Bowman、Gowry Sankar、Donald Pipowitch 和 Dave Finlay 對文件的提交和修訂。

附錄 G. 變更日誌

[CREF15]此章節在離開 Internet-Draft 狀態之前將被移除。

draft-handrews-json-schema-02

draft-handrews-json-schema-01

draft-handrews-json-schema-00

draft-wright-json-schema-01

draft-wright-json-schema-00

draft-zyp-json-schema-04

draft-zyp-json-schema-00

作者地址

Austin Wright (編輯) 電子郵件: [email protected]
Henry Andrews (編輯) 電子郵件: [email protected]
Ben Hutton (編輯) Wellcome Sanger Institute 電子郵件: [email protected] 網址: https://jsonschema.dev
Greg Dennis 奧克蘭, 紐西蘭 電子郵件: [email protected]