網際網路草案 JSON Schema 2022 年 6 月
Wright 等人 到期日:2022 年 12 月 18 日 [頁碼]
工作組
網際網路工程任務組
網際網路草案
draft-bhutton-json-schema-01
發布日期
預期狀態
資訊性
到期
作者
A. Wright,編輯
H. Andrews,編輯
B. Hutton,編輯
Postman
G. Dennis

JSON Schema:用於描述 JSON 文件的一種媒體類型

摘要

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/

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

本網際網路草案將於 2022 年 12 月 18 日到期。

目錄

1. 簡介

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

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

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

2. 慣例和術語

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

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

3. 概述

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

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

為了方便重複使用,關鍵字可以組織成詞彙表。詞彙表包含關鍵字列表,以及它們的語法和語義。方言被定義為一組詞彙表,以及在元綱要中識別的所需支援。

JSON 綱可以透過定義額外的詞彙表來擴充,或者以較不正式的方式定義任何詞彙表之外的額外關鍵字。無法識別的個別關鍵字只會將它們的值收集為註解,而對於無法識別的詞彙表的行為,可以在宣告正在使用哪些詞彙表時進行控制。

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

此外,本文件定義了一個建議的關鍵字詞彙表,用於有條件地應用子綱要,以及將子綱要應用於物件和陣列的內容。無論這些綱要是用於斷言驗證、註解還是兩者兼具,都需要此詞彙表或非常相似的詞彙表才能為非簡單 JSON 實例編寫綱要。雖然不是必要的核心詞彙表的一部分,但為了獲得最大的互通性,本文件包含此額外詞彙表,並強烈建議使用它。

用於結構驗證或超媒體註解等目的的進一步詞彙表定義於其他文件中。這些其他文件各自定義了一種方言,收集了為該文件目的編寫綱要所需的標準詞彙表。

4. 定義

4.1. JSON 文件

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

在 JSON 綱要中,由於它定義的資料模型,「JSON 文件」、「JSON 文字」和「JSON 值」等術語是可互換的。

JSON 綱要僅針對 JSON 文件定義。但是,任何可以根據 JSON 綱要資料模型解析或處理的文件或記憶體結構都可以根據 JSON 綱要進行解釋,包括 CBOR [RFC7049] 等媒體類型。

4.2. 實例

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

JSON 綱要定義於「application/json」或相容文件之上,包括具有「+json」結構語法後綴的媒體類型。

其中,本規範定義了「application/schema-instance+json」媒體類型,該類型定義了 URI 中片段的處理。

4.2.1. 實例資料模型

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

實例具有六種基本類型之一,以及取決於該類型的可能值範圍:

null
JSON「null」值
boolean
來自 JSON「true」或「false」值的「true」或「false」值
object
從 JSON「object」值到將字串映射到實例的屬性的無序集合
array
從 JSON「array」值的實例的有序列表
number
來自 JSON「number」值的任意精度、以 10 為底的十進制數值
string
來自 JSON「string」值的 Unicode 字碼點字串

因此,空格和格式設定問題,包括資料模型中相等的數字的不同詞彙表示形式,都在 JSON 綱要的範圍之外。希望處理詞彙表示形式中差異的 JSON 綱要 詞彙表 (第 8.1 節) 應定義關鍵字,以便精確解釋資料模型中的格式化字串,而不是依賴於使用原始 JSON 表示形式的 Unicode 字元。

由於物件不能具有兩個具有相同鍵的屬性,因此嘗試在單一物件中定義兩個具有相同鍵的屬性的 JSON 文件的行為未定義。

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

4.2.2. 實例相等性

如果兩個 JSON 實例屬於同一類型並根據資料模型具有相同的值,則稱它們相等。具體來說,這表示:

  • 兩者都是 null;或
  • 兩者都是 true;或
  • 兩者都是 false;或
  • 兩者都是字串,並且是相同的字碼點對字碼點;或
  • 兩者都是數字,並且具有相同的數學值;或
  • 兩者都是陣列,並且具有逐項相等的項目值;或
  • 兩者都是物件,並且其中一個的每個屬性都恰好有一個鍵與另一個的鍵相等的屬性,並且另一個屬性具有相等的值。

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

4.2.3. 非 JSON 實例

JSON Schema 可以與 JSON Schema 資料模型的超集合一起使用,其中實例可能在六種 JSON 資料類型之外。

在這種情況下,註解仍然適用;但大多數驗證關鍵字將不會有用,因為它們總是會通過或總是會失敗。

自訂詞彙表可以定義對核心資料模型超集合的支援。schema 本身可能只能在這個超集合中表達;例如,要使用 "const" 關鍵字。

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 的其他約束。

在同一個 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 物件是明確的,但 "false" schema 有許多可能的等效項。使用布林值可確保意圖對人類讀者和實作都是清楚的。

4.3.3. Schema 詞彙表

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

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

schema 詞彙表可以由從非正式描述到標準提案的任何內容定義,具體取決於對象和互通性期望。特別是,為了方便在非公開組織內使用詞彙表,詞彙表規範不需要在其使用範圍之外發布。

4.3.4. Meta-Schema

本身描述 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 資源是由 標準 [RFC6596]絕對 URI [RFC3986] 識別的 schema。如果產生的次要資源(如 RFC 3986 的第 3.5 節 [RFC3986] 所定義)與主要資源相同,則 schema 資源也可以由 URI(包括帶有片段的 URI)識別。當使用空片段時,或者當一個 schema 資源嵌入到另一個 schema 資源中時,可能會發生這種情況。任何帶有片段的 URI 都被認為是非標準的。

根 schema 是包含相關整個 JSON 文件的 schema。根 schema 始終是一個 schema 資源,其中 URI 的確定方式如 9.1.1 節所述。請注意,以另一種格式嵌入 schema 的文件不會在此意義上具有根 schema 資源。確切地說,這種用法如何符合 JSON Schema 文件和資源的概念將在未來的草稿中闡明。

某些關鍵字本身會採用 schema,允許 JSON Schema 嵌套:

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

在這個範例文件中,標題為「陣列項目」的 schema 是一個子 schema,而標題為「根」的 schema 是根 schema。

與根 schema 一樣,子 schema 要麼是一個物件,要麼是一個布林值。

8.2.1 節所述,JSON Schema 文件可以包含多個 JSON Schema 資源。在不加限定的情況下使用時,術語「根 schema」指的是文件的根 schema。在某些情況下,會討論資源的根 schema。資源的根 schema 是其最上層的 schema 物件,如果將資源提取到獨立的 JSON Schema 文件中,它也將是文件根 schema。

無論多個 schema 資源是嵌入還是透過參照連結,它們都以相同的方式處理,具有相同的可用行為。

5. 片段識別符號

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

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

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

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

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

6. 一般考量

6.1. JSON 值的範圍

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

6.2. 程式語言獨立性

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

6.3. 數學整數

某些程式語言和解析器對浮點數使用與整數不同的內部表示形式。

為了保持一致性,整數 JSON 數字不應使用小數部分進行編碼。

6.4. 正規表示式

關鍵字可以使用正規表示式來表達約束,或約束實例值為正規表示式。這些正規表示式應根據 ECMA-262,第 21.2.1 節 [ecma262] 中描述的正規表示式方言有效。

正規表示式應使用 "u" 旗標(或等效方式)來提供 Unicode 支援,或以符合 ECMA-262 定義的方式處理以提供 Unicode 支援。

此外,由於正規表示式結構的支援差異很大,schema 作者應將自己限制在以下正規表示式符號:

  • 個別 Unicode 字元,如 JSON 規格 [RFC8259] 所定義;
  • 簡單字元類別([abc])、範圍字元類別([a-z]);
  • 補集字元類別([^abc]、[^a-z]);
  • 簡單量詞:「+」(一個或多個)、「*」(零個或多個)、「?」(零個或一個),及其惰性版本("+?"、"*?"、"??");
  • 範圍量詞:「{x}」(恰好 x 個)、「{x,y}」(至少 x 個,至多 y 個)、「{x,}」(x 個或更多個),及其惰性版本;
  • 輸入開頭("^")和輸入結尾("$")錨點;
  • 簡單分組("(...)")和交替("|")。

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

6.5. 擴展 JSON Schema

任何實體都可以定義額外的 schema 關鍵字和 schema 詞彙表。除非有明確協議,schema 作者不應期望未明確記錄此類支援的實作支援這些額外的關鍵字和詞彙表。實作應將它們不支援的關鍵字視為註解,其中關鍵字的值為註解的值。

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

7. 關鍵字行為

JSON Schema 關鍵字分為幾個一般行為類別。斷言驗證實例是否滿足約束,產生布林結果。註解附加應用程式可以以任何它們認為適合的方式使用的資訊。應用程式將子 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"、"$ref" 和 "$dynamicRef" 核心關鍵字,以及 "base" JSON Hyper-Schema 關鍵字,都是此類行為的範例。

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

其他關鍵字可能會考慮在評估 schema 期間存在的動態範圍,通常與實例文件一起使用。最外層的動態範圍是開始處理的 schema 物件,即使它不是 schema 資源根。從此根 schema 到任何特定關鍵字的路徑(包括可能已解析的任何 "$ref" 和 "$dynamicRef" 關鍵字)被視為該關鍵字的「驗證路徑」。

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

動態範圍的概念主要與 "$dynamicRef" 和 "$dynamicAnchor" 一起使用,應被視為進階功能,並且在定義其他關鍵字時應謹慎使用。它也會在報告錯誤和收集的註解時出現,因為可能會以不同的動態範圍重複訪問相同的詞法範圍。在這種情況下,務必通知使用者產生錯誤或註解的動態路徑。

7.2. 關鍵字互動

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

7.3. 預設行為

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

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

由於註解收集可能會在計算和記憶體方面增加大量成本,因此實作可以選擇退出此功能。根據收集的註解指定的關鍵字應在適當時描述合理的替代方法。此方法在本文件中由 "items" 和 "additionalProperties" 關鍵字說明。

請注意,當關鍵字不可能使用此類替代方法時,不支援註解收集的實作將無法支援那些關鍵字或包含這些關鍵字的詞彙表。

7.4. 識別符號

識別符號為 schema 定義 URI,或影響如何在參考第 8.2.3 節中解析此類 URI,或兩者皆有。本文檔中定義的核心詞彙表定義了幾個識別關鍵字,其中最著名的是 "$id"。

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

雖然可以自訂識別符號關鍵字,但詞彙表設計人員應注意不要破壞核心關鍵字的功能。例如,本規範中的 "$dynamicAnchor" 關鍵字將其 URI 解析效果限制為匹配的 "$dynamicRef" 關鍵字,而不會干擾 "$ref" 的行為。

7.5. 應用程式

應用程式允許建構比單一 schema 物件可以完成的更複雜的 schema。針對schema 文件第 4.3 節評估實例,首先將根 schema第 4.3.5 節應用於完整的實例文件。從那裡開始,使用稱為應用程式的關鍵字來確定要應用哪些額外的 schema。此類 schema 可以就地應用於目前的位置,或應用於子位置。

要應用的 schema 可能以子 schema 的形式存在,這些子 schema 組成關鍵字值的全部或部分。或者,應用程式可以參考同一 schema 文件或不同文件中的其他位置的 schema。識別此類參考 schema 的機制由關鍵字定義。

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

註解第 7.7 節結果會與實例位置和 schema 關鍵字的位置一起保存,以便應用程式可以決定如何解譯多個值。

7.5.1. 參考和參照 Schema

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

雖然根架構(root schemas)和子架構(subschemas)是基於架構在架構文件中的位置的靜態概念,但被參考的架構(referenced schemas)和參考其他架構的架構(referencing schemas)則是動態的。在針對實例評估架構的過程中,不同的架構對可能會有不同的被參考和參考關係。

對於某些藉由參考來應用的修飾詞(by-reference applicators),例如 "$ref" (第 8.2.3.1 節),被參考的架構可以藉由靜態分析架構文件的詞法範圍來確定。其他修飾詞,例如 "$dynamicRef"(搭配 "$dynamicAnchor"),可能會使用動態範圍,因此只能在以實例評估架構的過程中解析。

7.6. 斷言(Assertions)

JSON Schema 可用於對 JSON 文件斷言約束,這些約束會使驗證通過或失敗。此方法可用於驗證是否符合約束,或記錄滿足約束所需條件。

當針對架構斷言評估實例時,JSON Schema 實作會產生單一布林值結果。

實例只能使架構中存在的斷言失敗。

7.6.1. 斷言與實例基本類型

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

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

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

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

如果 "maxLength" 也將實例類型限制為字串,則表達會變得更加繁瑣,因為如撰寫的範例實際上不允許 null 值。除非另有明確規定,否則每個關鍵字都會單獨評估,因此如果 "maxLength" 將實例限制為字串,則在 "type" 中包含 "null" 將不會有任何作用。

7.7. 註解(Annotations)

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

註解會附加到實例中的特定位置。由於許多子架構可以應用於任何單一位置,因此應用程式可能需要決定如何處理由不同架構物件中相同架構關鍵字附加到相同實例位置的不同註解值。

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

除非另有規定,否則註解關鍵字的值就是關鍵字的值。但是,其他行為也是可能的。例如,JSON Hyper-Schema [json-hyper-schema] 的 "links" 關鍵字是一種複雜的註解,它會根據部分實例資料產生值。

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

7.7.1. 收集註解

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

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

  • 產生註解的關鍵字名稱
  • 其附加的實例位置,以 JSON 指標表示
  • 架構位置路徑,指示如何跟隨諸如 "$ref" 之類的參考關鍵字來到達絕對架構位置。
  • 附加關鍵字的絕對架構位置,以 URI 表示。如果它與上述的架構位置路徑相同,則可以省略。
  • 附加的值
7.7.1.1. 區分多個值

應用程式可以根據提供值的架構位置來決定要使用多個註解值中的哪一個。這樣做的目的是為了允許彈性使用。收集架構位置有助於這種使用。

例如,考慮以下架構,它使用了來自 驗證規範 [json-schema-validation] 的註解和斷言:

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

{
    "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" 架構。該架構使用 "title"、"description" 和 "default" 註解。因此,應用程式必須決定如何處理功能 A 的額外 "default" 值,以及功能 B 的額外 "description" 值。

應用程式程式設計人員和架構作者需要就用法達成一致。在此範例中,我們假設他們同意將使用最明確的 "default" 值,任何額外的、更通用的 "default" 值將被靜默忽略。我們也假設他們同意使用所有 "description" 文字,從最通用的開始,到最明確的結束。這要求架構作者撰寫以這種方式組合時有效的描述。

應用程式可以使用架構位置路徑來確定哪些值是什麼。功能即時 "enabled" 屬性架構中的值更明確,而透過 "$ref" 參考的可重複使用架構下的值則更通用。架構位置路徑將顯示每個值是否是透過跨越 "$ref" 找到的。

因此,功能 A 將使用 true 的預設值,而功能 B 將使用 null 的通用預設值。功能 A 將僅具有來自 "enabledToggle" 架構的通用描述,而功能 B 將使用該描述,並附加其本地定義的描述,說明如何解釋 null 值。

請注意,不同的應用程式可能會採用其他合理的方法。例如,應用程式可能會認為 "default" 的兩個不同值是錯誤,而不管它們的架構位置如何。

7.7.1.2. 註解與斷言

產生 false 斷言結果的架構物件不得產生任何註解結果,無論是來自其自己的關鍵字還是來自子架構中的關鍵字。

請注意,整體架構結果仍然可能包含從其他架構位置收集的註解。給定以下架構:

{
    "oneOf": [
        {
            "title": "Integer Value",
            "type": "integer"
        },
        {
            "title": "String Value",
            "type": "string"
        }
    ]
}

針對實例 "This is a string",因為該架構物件中的類型斷言失敗,所以標題註解 "Integer Value" 會被捨棄。標題註解 "String Value" 會保留,因為該實例通過字串類型斷言。

7.7.1.3. 註解與修飾詞

除了可能定義自己的註解結果外,修飾詞關鍵字還會聚合在其子架構或被參考架構中收集的註解。

7.8. 保留位置

第四類關鍵字僅保留一個位置來保存可重複使用的組件或架構作者感興趣但不可重複使用的資料。這些關鍵字不會影響驗證或註解結果。它們在核心詞彙中的目的是確保這些位置可用於特定目的,並且不會被擴展關鍵字重新定義。

雖然這些關鍵字不會直接影響結果,如 9.4.2 節中所述,為可重複使用架構保留位置的無法識別的擴展關鍵字,在某些情況下可能會與參考產生不良的互動。

7.9. 載入實例資料

雖然作為此文件或相關文件一部分定義的詞彙均未定義可能會針對和/或載入實例資料的關鍵字,但其他詞彙可能希望這樣做。

可以定義關鍵字以使用 JSON 指標或相對 JSON 指標來檢查目前評估位置之外的實例部分。

允許使用相對 JSON 指標調整位置的關鍵字,如果需要預設值,則應預設使用目前位置。

8. JSON Schema 核心詞彙

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

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

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

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

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

對應的 meta-schema 目前的 URI 為:https://json-schema.dev.org.tw/draft/2020-12/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 與詞彙是分開的,以便允許詞彙以不同的方式組合,並允許 meta-schema 作者施加額外的約束,例如禁止某些關鍵字,或執行異常嚴格的語法驗證,這可能在開發和測試週期中完成。每個詞彙通常會識別一個只包含該詞彙關鍵字的 meta-schema。

Meta-schema 編寫是 JSON Schema 的進階用法,因此 meta-schema 功能的設計強調靈活性,而不是簡潔性。

8.1.1. "$schema" 關鍵字

"$schema" 關鍵字既作為 JSON Schema 方言識別符,也作為 JSON Schema 資源的識別符,它描述了為此特定方言編寫的一組有效 schema。

這個關鍵字的值必須是 URI [RFC3986](包含 scheme),且此 URI 必須正規化。目前的 schema 必須針對此 URI 識別的 meta-schema 有效。

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

"$schema" 關鍵字應在文件根 schema 物件中使用,並且可以在嵌入式 schema 資源的根 schema 物件中使用。它不得出現在非資源根 schema 物件中。如果文件根 schema 中不存在此關鍵字,則產生的行為是由實作定義的。

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

8.1.2. "$vocabulary" 關鍵字

"$vocabulary" 關鍵字在 meta-schema 中使用,以識別該 meta-schema 所描述的 schema 中可使用的詞彙。它也用於指示每個詞彙是必需的還是可選的,意思是說,實作必須理解所需的詞彙才能成功處理 schema。這些資訊共同構成了一種方言。實作所理解的任何詞彙都必須以與詞彙中包含的語義定義一致的方式處理。

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

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

物件屬性的值必須是布林值。如果值為 true,則不識別該詞彙的實作必須拒絕處理任何使用 "$schema" 宣告此 meta-schema 的 schema。如果值為 false,則不識別該詞彙的實作應繼續處理此類 schema。如果實作理解該詞彙,則該值沒有影響。

根據 6.5,無法識別的關鍵字應被視為註釋。對於由無法識別的詞彙定義的關鍵字也是如此。目前無法區分在詞彙中定義的無法識別的關鍵字與不屬於任何詞彙的關鍵字。

"$vocabulary" 關鍵字應在任何打算用作 meta-schema 的 schema 文件的根 schema 中使用。它不得出現在子 schema 中。

"$vocabulary" 關鍵字在未作為 meta-schema 處理的 schema 文件中必須被忽略。這允許針對自己的 meta-schema M' 驗證 meta-schema M,而無需驗證器理解 M 宣告的詞彙。

8.1.2.1. 預設詞彙

如果缺少 "$vocabulary",實作可以根據 meta-schema 來判斷行為,如果它是從引用 schema 的 "$schema" 關鍵字的 URI 值中識別出來的。這是在詞彙存在之前,行為(例如 Hyper-Schema 的使用)如何被識別的方式。

如果 schema 引用的 meta-schema 無法識別或遺失,則行為由實作定義。如果實作繼續處理 schema,則必須假設使用核心詞彙。如果實作是為特定目的而建置的,則應假設使用所有與該目的最相關的詞彙。

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

8.1.2.2. 詞彙的不可繼承性

請注意,對 "$vocabulary" 的處理限制表示,使用 "$ref" 或類似關鍵字引用其他 meta-schema 的 meta-schema 不會自動繼承這些其他 meta-schema 的詞彙宣告。所有此類宣告都必須在每個打算用作 meta-schema 的 schema 文件的根部重複。這在範例 meta-schema (附錄 D.2)中得到了證明。 這個要求允許實作在每個 meta-schema 的單個位置找到所有詞彙要求資訊。由於 schema 的可擴展性意味著有無限種可能的方法可以通過引用來組合更細粒度的 meta-schema,因此要求實作預測所有可能性並在引用的 meta-schema 中搜尋詞彙會過於繁瑣。

8.1.3. Meta-Schema 與詞彙 URI 的更新

為了修正錯誤,可以在規範草案之間發布更新的詞彙和 meta-schema URI。實作應考慮在此規範草案之後和下一個規範草案之前的日期標記的 URI,以表示與此處列出的語法和語義相同。

8.2. 基本 URI、錨點和反向引用

為了區分龐大生態系統中的 schema,schema 由 URI [RFC3986] 識別,並且可以通過指定其 URI 來嵌入對其他 schema 的引用。

多個關鍵字可以接受相對 URI 參考 [RFC3986],或用於建構相對 URI 參考的值。對於這些關鍵字,有必要建立基本 URI 以便解析參考。

8.2.1. "$id" 關鍵字

"$id" 關鍵字使用其 標準 [RFC6596] URI 來識別 schema 資源。

請注意,此 URI 是一個識別符,不一定是網路定位器。在網路可尋址 URL 的情況下,schema 不需要從其標準 URI 下載。

如果存在,此關鍵字的值必須是一個字串,並且必須表示一個有效的 URI 參考 [RFC3986]。此 URI 參考應正規化,並且必須解析為 絕對 URI [RFC3986](不帶片段)或帶有空片段的 URI。

不建議使用空片段形式,僅為了向後相容性而保留,因為 application/schema+json 媒體類型定義帶有空片段的 URI 與刪除片段的相同 URI 識別相同的資源。但是,由於此等效性不屬於 RFC 3986 正規化過程 [RFC3986] 的一部分,實作者和 schema 作者不能依賴於通用 URI 庫來理解它。

因此,「$id」絕對不能包含非空的片段(fragment),並且不應包含空的片段。絕對 URI 形式必須被視為標準 URI,無論是否存在空的片段。目前允許空的片段,是因為較舊的中繼綱要在其 $id(或之前的 id)中有空的片段。未來的草案可能會完全禁止在「$id」中使用空的片段。

根據 RFC 3986 第 5.1.1 節 [RFC3986] 中關於嵌入內容的基礎 URI 規定,絕對 URI 也作為綱要資源中關鍵字的相對 URI 參照的基礎 URI。

子綱要中存在「$id」表示該子綱要在單一綱要文件中構成一個獨立的綱要資源。此外,根據 RFC 3986 第 5.1.2 節 [RFC3986] 中關於封裝實體的規定,如果子綱要中的「$id」是一個相對 URI 參照,則解析該參照的基礎 URI 是父綱要資源的 URI。

如果沒有父綱要物件明確使用「$id」將自己識別為資源,則基礎 URI 為整個文件的 URI,如 前一節第 9.1.1 節所述的步驟建立。

8.2.1.1. 識別根綱要

JSON 綱要文件的根綱要應包含一個帶有絕對 URI [RFC3986](包含 scheme,但不包含片段)的「$id」關鍵字。

8.2.2. 定義與位置無關的識別符號

使用 JSON 指標片段需要了解綱要的結構。在編寫旨在提供可重複使用綱要的綱要文件時,最好使用未與任何特定結構位置綁定的純名稱片段。這樣就可以在不更新 JSON 指標參照的情況下重新定位子綱要。

「$anchor」和「$dynamicAnchor」關鍵字用於指定此類片段。它們是識別符號關鍵字,只能用於創建純名稱片段,而不是像「$id」那樣的絕對 URI。

附加結果片段的基礎 URI 是包含相關「$anchor」或「$dynamicAnchor」的綱要資源的標準 URI。如上一節所述,這可以是同一個或父綱要物件中最近的「$id」,也可以是根據 RFC 3986 確定的文件基礎 URI。

與 URI 的通常用法不同,「$dynamicAnchor」表示當與「$dynamicRef」關鍵字一起使用時,該片段是一個擴展點。此低階、進階功能使得擴展諸如中繼綱要之類的遞迴綱要變得更容易,而不會對該擴展施加任何特定語意。有關詳細信息,請參閱有關 「$dynamicRef」第 8.2.3.2 節的章節。

在大多數情況下,一般的片段行為既足夠又更直觀。因此,建議使用「$anchor」來創建純名稱片段,除非有明確需要使用「$dynamicAnchor」。

如果存在,此關鍵字的值必須是一個字串,並且必須以字母 ([A-Za-z]) 或底線 ("_") 開頭,後跟任意數量的字母、數字 ([0-9])、連字符 ("-")、底線 ("_") 和句點 (".")。這符合 XML 的 NCName 產生式 [xml-names] 的 US-ASCII 部分。請注意,錨點字串不包含 "#" 字元,因為它不是 URI 參照。「$anchor": "foo" 在 URI 中使用時會變成片段 "#foo"。請參閱下面的完整範例。

在同一資源中多次指定相同的片段名稱,使用「$anchor」和/或「$dynamicAnchor」的任何組合,其效果是未定義的。如果檢測到此類用法,實作可以引發錯誤。

8.2.3. 綱要參照

可以使用多個關鍵字來參照要應用於目前實例位置的綱要。「$ref」和「$dynamicRef」是應用關鍵字,將參照的綱要應用於實例。

由於「$ref」和「$dynamicRef」的值是 URI 參照,這允許將綱要外部化或分割到多個文件中,並提供透過自我參照來驗證遞迴結構的能力。

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

8.2.3.1. 使用「$ref」的直接參照

「$ref」關鍵字是一個應用程式,用於參照靜態識別的綱要。它的結果是參照綱要的結果。請注意,此決定結果的定義表示其他關鍵字可以與同一綱要物件中的「$ref」一起出現。

「$ref」關鍵字的值必須是一個字串,該字串是 URI 參照。根據目前的 URI 基礎解析,它會產生要應用的綱要 URI。此解析可在綱要載入時安全執行,因為評估實例的過程無法改變參照的解析方式。

8.2.3.2. 使用「$dynamicRef」的動態參照

「$dynamicRef」關鍵字是一個應用程式,允許將完整解析延遲到運行時,屆時會在評估實例時每次遇到時都進行解析。

「$dynamicRef」與「$dynamicAnchor」一起實作了一種協作擴展機制,該機制主要用於遞迴綱要(參照自身的綱要)。擴展點和運行時確定的擴展目標都使用「$dynamicAnchor」定義,並且只有在使用「$dynamicRef」參照時才會表現出運行時的動態行為。

「$dynamicRef」屬性的值必須是一個字串,該字串是 URI 參照。根據目前的 URI 基礎解析,它會產生用作運行時解析起點的 URI。此初始解析可在綱要載入時安全執行。

如果初始解析的起點 URI 包含由「$dynamicAnchor」關鍵字建立的片段,則初始 URI 必須替換為 動態範圍第 7.1 節中最外層綱要資源的 URI(包括片段),該資源使用「$dynamicAnchor」定義了名稱相同的片段。

否則,其行為與「$ref」相同,並且不需要運行時解析。

有關使用這些關鍵字的完整範例,請參閱附錄 C2019 年之前的草案中的超綱要中繼綱要與此草案之間的差異顯著地展示了這些關鍵字的實用性。

8.2.4. 使用「$defs」重用綱要

「$defs」關鍵字為綱要作者保留了一個位置,以便將可重複使用的 JSON 綱要內嵌到更通用的綱要中。該關鍵字不會直接影響驗證結果。

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

例如,以下是一個描述正整數陣列的綱要,其中正整數約束是「$defs」中的子綱要:

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

8.3. 使用「$comment」的註解

此關鍵字為綱要作者保留一個位置,以便向綱要的讀者或維護者添加註解。

此關鍵字的值必須是一個字串。實作絕不能向終端使用者顯示此字串。用於編輯綱要的工具應支援顯示和編輯此關鍵字。此關鍵字的值可用於旨在供使用綱要的開發人員使用的除錯或錯誤輸出中。

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

將其他媒體類型或程式設計語言與 application/schema+json 相互轉換的工具可以選擇將該媒體類型或程式設計語言的原生註解轉換為「$comment」值,或從「$comment」值轉換而來。當原生註解和「$comment」屬性都存在時,此類轉換的行為取決於實作。

實作可以在處理過程中的任何時候刪除「$comment」值。特別是,這允許在部署的綱要大小是一個問題時縮短綱要。

實作絕不能根據「$comment」屬性的存在、不存在或內容採取任何其他操作。特別是,「$comment」的值絕不能作為註解結果收集。

9. 載入和處理綱要

9.1. 載入綱要

9.1.1. 初始基本 URI

RFC3986 第 5.1 節 [RFC3986] 定義了如何確定文件的預設基本 URI。

訊息上,綱要的初始基本 URI 是找到它的 URI,無論是網路位置、本機檔案系統,還是任何其他可透過任何已知協定的 URI 識別的情況。

如果綱要文件沒有使用 "$id"(嵌入在內容中)定義明確的基本 URI,則基本 URI 是根據 RFC 3986 第 5 節 [RFC3986] 確定的。

如果沒有已知來源,或者沒有已知來源的 URI 協定,則可以使用 RFC 3986 第 5.1.4 節 [RFC3986] 中描述的適當實作特定的預設 URI。建議實作應記錄它們假設的任何預設基本 URI。

如果綱要物件嵌入在其他媒體類型的文件中,則初始基本 URI 會根據該媒體類型的規則確定。

除非先前章節中描述的 "$id" 關鍵字出現在根綱要中,否則此基本 URI 應被視為綱要文件根綱要資源的正規 URI。

9.1.2. 載入參考的綱要

使用 URI 來識別遠端綱要並不一定表示會下載任何內容,而是 JSON 綱要實作應該提前了解它們將使用哪些綱要以及識別它們的 URI。

當下載綱要時,例如由通用使用者代理程式下載,該程式直到執行時才知道要下載哪些綱要,請參閱 超媒體使用方式第 9.5.1 節

實作應能夠將任意 URI 與任意綱要建立關聯,和/或自動關聯綱要的 "$id"-給定 URI,具體取決於驗證器對綱要的信任程度。這些 URI 和綱要可以在處理實例之前提供給實作,或者可以在處理綱要文件時記錄,產生如附錄 A 所示的關聯。

一個綱要可以(並且很可能)有多個 URI,但一個 URI 無法識別多個綱要。當多個綱要嘗試識別為相同的 URI 時,驗證器應引發錯誤條件。

9.1.3. 偵測中繼綱要

如果因為另一個綱要的 "$schema" 關鍵字將其識別為中繼綱要而正在檢查一個綱要,則實作必須將其識別為中繼綱要。這表示單個綱要文件有時可能會被視為常規綱要,而其他時候則被視為中繼綱要。

在檢查一個作為其自身中繼綱要的綱要的情況下,當實作開始將其作為常規綱要處理時,它會按照這些規則進行處理。但是,當由於檢查其自身的 "$schema" 值而第二次載入時,它會被視為中繼綱要。因此,同一個文件會在一個會話過程中以兩種方式進行處理。

實作可以允許將綱要明確地作為中繼綱要傳遞,以用於實作特定的目的,例如預先載入常用的中繼綱要並預先檢查其詞彙支援要求。中繼綱要作者不得期望這些功能在不同的實作之間具有互通性。

9.2. 取消參考

綱要可以透過任何已給定的 URI 進行識別,包括 JSON 指標或其由 "$id" 直接給定的 URI。在所有情況下,取消參考 "$ref" 參考都涉及首先根據 RFC 3986 [RFC3986] 針對目前基本 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> 綱要時,它會針對目前基本 URI 將 "$anchor" 值解析為片段名稱,以形成 <https://example.net/root.json#item>。

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

當實作遇到對 "other.json" 的參考時,它會將其解析為 <https://example.net/other.json>,這未在此文件中定義。如果具有該識別碼的綱要已以其他方式提供給實作,則也可以自動使用它。當參考的綱要未知時,實作應執行哪些操作?在哪些情況下允許自動網路取消參考?是否有同源策略?使用者可配置的選項?在超綱要描述的演變 API 的情況下,預計會將新的綱要動態新增到系統中,因此將預先載入綱要文件設定為絕對要求是不可行的。

9.2.1. JSON 指標片段和嵌入的綱要資源

由於 JSON 指標 URI 片段是根據綱要文件的結構建構的,因此可以使用相對於其自身正規 URI 或相對於任何包含資源的 URI 的 JSON 指標片段來識別嵌入的綱要資源及其子綱要。

從概念上講,一組連結的綱要資源的行為應該相同,無論每個資源是使用 綱要參考第 8.2.3 節 連接的單獨文件,還是結構化為單個文件,其中一個或多個綱要資源嵌入為子綱要。

由於當嵌入的綱要移動到單獨的文件並被參考時,相對於父綱要資源的 URI 的涉及 JSON 指標片段的 URI 不再有效,因此應用程式和綱要不應使用此類 URI 來識別嵌入的綱要資源或其中的位置。

考慮以下綱要文件,其中包含嵌入其中的另一個綱要資源:

{
    "$id": "https://example.com/foo",
    "items": {
        "$id": "https://example.com/bar",
        "additionalProperties": { }
    }
}

URI "https://example.com/foo#/items" 指向 "items" 綱要,該綱要是一個嵌入的資源。但是,該綱要資源的正規 URI 是 "https://example.com/bar"。

對於該嵌入資源內的 "additionalProperties" 綱要,URI "https://example.com/foo#/items/additionalProperties" 指向正確的物件,但該物件相對於其資源正規 URI 的 URI 是 "https://example.com/bar#/additionalProperties"。

現在考慮以下兩個綱要資源,它們使用 "$ref" 的 URI 值透過參考連結:

{
    "$id": "https://example.com/foo",
    "items": {
        "$ref": "bar"
    }
}

{
    "$id": "https://example.com/bar",
    "additionalProperties": { }
}

在這裡,我們看到 "https://example.com/bar#/additionalProperties" 使用附加到 "bar" 綱要資源正規 URI 的 JSON 指標片段仍然有效,而 "https://example.com/foo#/items/additionalProperties" 則不再解析為任何內容,它依賴於附加到 "foo" 綱要資源正規 URI 的 JSON 指標片段。

另請注意,"https://example.com/foo#/items" 在這兩種排列方式中都有效,但會解析為不同的值。此 URI 的作用類似於資源的擷取 URI。雖然此 URI 有效,但除非特別需要識別第二種(非嵌入式)排列方式中包含 "$ref" 的物件,否則使用嵌入式或參考資源的 "$id" 會更穩健。

實作可以選擇不支援透過使用正規 URI 以外的基本 URI(加上相對於該基本 URI 的 JSON 指標片段)來尋址綱要資源內容。因此,綱要作者不應依賴此類 URI,因為使用它們可能會降低互通性。這是為了避免要求實作追蹤每個可能的基礎 URI 和 JSON 指標片段的整個堆疊,因為如果重新組織綱要資源,除了其中一個之外的所有其他都會很脆弱。有些人認為這很容易,所以沒有理由禁止它,而另一些人則認為它會使綱要識別複雜化,應該禁止。我們鼓勵就此主題提供回饋。經過一些討論,我們認為我們需要刪除使用「正規」一詞,而改為談論跨綱要資源邊界參考的 JSON 指標作為未定義甚至是被禁止的行為(https://github.com/json-schema-org/json-schema-spec/issues/937, https://github.com/json-schema-org/json-schema-spec/issues/1183)

附錄 A 中提供了此類非正規 URI 建構的更多範例,以及要使用的適當的基於正規 URI 的片段。

9.3. 複合文件

複合綱要文件定義為 JSON 文件(有時稱為「捆綁」綱要),它將多個嵌入式 JSON 綱要資源捆綁到同一個文件中,以方便傳輸。

每個嵌入式綱要資源都必須被視為單獨的綱要資源,遵循標準的綱要載入和處理要求,包括確定詞彙支援。

9.3.1. 捆綁

建立複合綱要文件的捆綁過程定義為採用對外部綱要資源的參考(例如 "$ref")並將參考的綱要資源嵌入到參考文件中。執行捆綁時應確保基本文件和任何參考/嵌入的文件中的所有 URI(用於參考)都不需要更改。

每個嵌入式 JSON 綱要資源都必須使用 "$id" 關鍵字以 URI 識別自身,並且應在綱要資源的根目錄中使用 "$schema" 關鍵字來識別它正在使用的方言。建議 "$id" 的 URI 識別碼值為絕對 URI。

當由參照應用程式(by-reference applicator)引用的綱要資源被綑綁時,建議將綱要資源放置在包含綱要的根目錄下的 "$defs" 物件的值中。現在嵌入的綱要資源的 "$defs" 的鍵值可以是綑綁綱要的 "$id" 或其他形式的應用程式定義的唯一識別符(例如 UUID)。此鍵值不打算在 JSON 綱要中被參照,但應用程式可以使用它來輔助綑綁過程。

綱要資源可以嵌入在 "$defs" 以外的位置,其中該位置被定義為綱要值。

綑綁的綱要資源不得透過替換它所參照的綱要物件,或將綱要資源包裹在其他應用程式關鍵字中來進行綑綁。

為了產生相同的輸出,包含綱要文件中對先前外部綱要資源的參照不得更改,並且現在使用嵌入綱要資源的 "$id" 解析為綱要。此類相同的輸出包括驗證評估,以及在產生的註釋或錯誤中使用的 URI 或路徑。

雖然綑綁過程通常是建立複合綱要文件的主要方法,但也可能且預期會有部分文件是手動建立的,可能先前沒有獨立存在的綱要資源。

9.3.2. 不同及預設方言

當單一文件中存在多個綱要資源時,未定義應使用哪種方言處理的綱要資源,必須使用與封閉資源相同的方言進行處理。

由於任何可以被參照的綱要也可以被嵌入,因此嵌入的綱要資源可以使用其封閉資源中的 "$schema" 值來指定不同的處理方言。

9.3.3. 驗證

鑒於複合綱要文件可能具有將自己識別為使用不同方言的嵌入資源,因此不應通過將元綱要作為實例應用於複合綱要文件來驗證這些文件。建議提供替代的驗證過程來驗證綱要文件。每個綱要資源都應針對其相關的元綱要單獨驗證。如果您知道要驗證的綱要是什麼,您可以通過使用 "$id" 來識別綱要是否為複合綱要文件,當 "$id" 不是在文件的根目錄中使用時,它會識別一個嵌入的資源。

如果複合綱要文件中所有嵌入資源都識別為使用相同的方言,或者省略了 "$schema" 並因此預設為封閉資源的方言,則可以通過應用適當的元綱要來驗證。

9.4. 注意事項

9.4.1. 防止無限遞迴

綱要不得針對實例進入無限迴圈。例如,如果兩個綱要 "#alice" 和 "#bob" 都具有一個 "allOf" 屬性,該屬性參照另一個,則天真的驗證器可能會陷入無限遞迴迴圈,試圖驗證該實例。綱要不應使用像這樣的無限遞迴巢狀結構;其行為是未定義的。

9.4.2. 參照到可能的非綱要

子綱要物件(或布林值)透過它們與已知應用程式關鍵字或位置保留關鍵字(例如"$defs"第 8.2.4 節)一起使用來識別,這些關鍵字將一個或多個子綱要作為值。這些關鍵字可能是 "$defs" 和本文檔中的標準應用程式,或來自已知詞彙表的擴展關鍵字,或特定於實作的自訂關鍵字。

未知關鍵字的多層結構能夠引入巢狀子綱要,這將受到 "$id" 的處理規則的約束。因此,在這種無法識別的結構中具有參照目標無法可靠地實現,並且產生的行為是未定義的。同樣,在已知關鍵字下的參照目標(已知該值不是綱要)也會導致未定義的行為,以避免實作需要檢測此類目標的負擔。這些情況類似於通過 HTTP 提取綱要,但收到 Content-Type 不是 application/schema+json 的回應。實作當然可以嘗試將其解釋為綱要,但原始伺服器不保證它實際上是任何此類東西。因此,將其解釋為這樣會產生安全隱憂,並可能產生不可預測的結果。

請注意,與 "$defs" 具有相同語法和語義的單層自訂關鍵字不允許任何介入的 "$id" 關鍵字,因此在嘗試將任何參照目標用作綱要的實作下,它們將正確運作。但是,此行為是特定於實作的,並且不得為了互通性而依賴它。

9.5. 關聯實例和綱要

9.5.1. 用於超媒體

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

9.5.1.1. 連結到綱要

建議由綱要描述的實例使用連結關係 "describedby",提供連結到可下載的 JSON 綱要,如連結資料協定 1.0,第 8.1 節 [W3C.REC-ldp-20150226]中所定義。

在 HTTP 中,可以使用連結標頭 [RFC8288]將此類連結附加到任何回應。此類標頭的一個範例是:

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

9.5.1.2. 透過 HTTP 使用

當在網路上的超媒體系統中使用時,HTTP [RFC7231]通常是用於分發綱要的首選協定。如果行為不當的用戶端比必要時更頻繁地從網路提取綱要,那麼這可能會給伺服器維護者帶來問題,而實際上可以將綱要快取一段時間。

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

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

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

用戶端應能夠使用 "From" 標頭發出請求,以便伺服器運營商可以聯絡潛在行為不當的腳本的擁有者。

10. 應用子綱要的詞彙表

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

未使用 "$vocabulary" 的元綱要應被視為要求此詞彙表,就像其 URI 以 true 值存在一樣。

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

相應元綱要的目前 URI 為:https://json-schema.dev.org.tw/draft/2020-12/meta/applicator

10.1. 關鍵字獨立性

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

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

10.2. 用於就地應用子綱要的關鍵字

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

這些關鍵字的子綱要會完全獨立地評估實例,因此一個此類子綱要的結果不得影響同級子綱要的結果。因此,子綱可以以任何順序應用。

10.2.1. 用於使用邏輯應用子綱要的關鍵字

這些關鍵字對應於用於組合或修改子綱要的布林斷言結果的邏輯運算符。它們對註釋收集沒有直接影響,儘管它們允許將相同的註釋關鍵字以不同的值應用於實例位置。註釋關鍵字定義了它們自己組合此類值的規則。

10.2.1.1. allOf

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

如果實例針對此關鍵字的值定義的所有綱要都成功驗證,則此實例可針對此關鍵字成功驗證。

10.2.1.2. anyOf

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

如果實例針對此關鍵字的值定義的至少一個綱要成功驗證,則此實例可針對此關鍵字成功驗證。請注意,當收集註釋時,必須檢查所有子綱要,以便從每個成功驗證的子綱要中收集註釋。

10.2.1.3. oneOf

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

若且唯若實例完全符合此關鍵字的值所定義的其中一個綱要,則此實例即通過驗證。

10.2.1.4. not

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

若實例未能成功通過此關鍵字所定義的綱要驗證,則此實例即通過此關鍵字的驗證。

10.2.2. 用於有條件地套用子綱要的關鍵字

其中三個關鍵字協同運作,以根據另一個子綱要的結果來實作子綱要有條件的套用。第四個關鍵字則是特定條件案例的捷徑。

「if」、「then」和「else」不得跨子綱要界限互相影響。換句話說,一個「allOf」分支中的「if」不得影響另一個分支中的「then」或「else」。

當「if」、「then」或「else」不存在時,沒有預設行為。特別是,它們不得被視為存在且帶有空的綱要,且當「if」不存在時,「then」和「else」都必須完全忽略。

10.2.2.1. if

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

此關鍵字的子綱要的驗證結果對整體驗證結果沒有直接影響。相反地,它會控制評估「then」或「else」關鍵字的哪個。

若實例成功通過此關鍵字的子綱要驗證,則也必須成功通過「then」關鍵字的子綱要值驗證(如果存在)。

若實例未能通過此關鍵字的子綱要驗證,則也必須成功通過「else」關鍵字的子綱要值驗證(如果存在)。

如果正在收集註解第 7.7 節,則會以通常的方式從此關鍵字的子綱要收集,包括當關鍵字存在而沒有「then」或「else」時。

10.2.2.2. then

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

當「if」存在,且實例成功通過其子綱要驗證時,若實例也成功通過此關鍵字的子綱要驗證,則對此關鍵字的驗證即成功。

當「if」不存在,或當實例未能通過其子綱要驗證時,此關鍵字不起作用。在這種情況下,實作必須不得為了驗證或註解收集目的,對此關鍵字評估實例。

10.2.2.3. else

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

當「if」存在,且實例未能通過其子綱要驗證時,若實例成功通過此關鍵字的子綱要驗證,則對此關鍵字的驗證即成功。

當「if」不存在,或當實例成功通過其子綱要驗證時,此關鍵字不起作用。在這種情況下,實作必須不得為了驗證或註解收集目的,對此關鍵字評估實例。

10.2.2.4. dependentSchemas

此關鍵字指定如果實例為物件且包含特定屬性時,會評估的子綱要。

此關鍵字的值必須為物件。物件中的每個值都必須是有效的 JSON 綱要。

如果物件索引鍵是實例中的屬性,則整個實例必須通過子綱要驗證。它的使用取決於屬性的存在。

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

10.3. 將子綱要套用至子實例的關鍵字

每個關鍵字都會定義將其子綱要套用至子實例(特別是物件屬性和陣列項目)並結合其結果的規則。

10.3.1. 將子綱要套用至陣列的關鍵字

10.3.1.1. prefixItems

「prefixItems」的值必須為有效的 JSON 綱要的非空陣列。

如果實例的每個元素都通過相同位置(如果有的話)的綱要驗證,則驗證成功。此關鍵字不會限制陣列的長度。如果陣列比此關鍵字的值長,則此關鍵字只驗證相符長度的前綴。

此關鍵字會產生註解值,該註解值是此關鍵字套用子綱要的最大索引。如果子綱要已套用至實例的每個索引,則該值可能是布林值 true,例如「items」關鍵字產生的值。此註解會影響「items」和「unevaluatedItems」的行為。

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

10.3.1.2. items

「items」的值必須為有效的 JSON 綱要。

此關鍵字會將其子綱要套用至索引大於同一個綱要物件中「prefixItems」陣列長度的所有實例元素,如該「prefixItems」關鍵字的註解結果所報告。如果不存在此類註解結果,「items」會將其子綱要套用至所有實例陣列元素。 請注意,沒有「prefixItems」的「items」的行為與先前草案中「items」的綱要形式相同。當「prefixItems」存在時,「items」的行為與先前的「additionalItems」關鍵字相同。

如果「items」子綱要套用至實例陣列中的任何位置,它會產生布林值 true 的註解結果,表示已針對此關鍵字的子綱要評估所有剩餘的陣列元素。此註解會影響「未評估」詞彙中「unevaluatedItems」的行為。

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

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

10.3.1.3. contains

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

如果陣列實例的至少一個元素通過給定綱要的驗證,則陣列實例對「contains」有效,除非「minContains」存在且值為 0,在這種情況下,即使沒有任何元素通過給定綱要的驗證,陣列實例也必須被視為對「contains」關鍵字有效。

此關鍵字會產生註解值,該註解值是當此關鍵字套用其子綱要時,成功通過驗證的索引的陣列,並依遞增順序排列。如果子綱要在套用至實例的每個索引時成功通過驗證,則該值可能是布林值「true」。如果此關鍵字的綱要所套用的實例陣列為空,則註解必須存在。

此註解會影響「未評估」詞彙中「unevaluatedItems」的行為,並且也可用於實作「驗證」詞彙中的「minContains」和「maxContains」關鍵字。

即使找到第一個匹配項後,子綱要也必須套用至每個陣列元素,以便收集其他關鍵字使用的註解。這是為了確保收集所有可能的註解。

10.3.2. 將子綱要套用至物件的關鍵字

10.3.2.1. properties

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

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

此關鍵字的註解結果是此關鍵字比對到的實例屬性名稱的集合。此註解會影響此詞彙中的「additionalProperties」以及「未評估」詞彙中的「unevaluatedProperties」的行為。

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

10.3.2.2. patternProperties

「patternProperties」的值必須為物件。此物件的每個屬性名稱都應該是有效的規則運算式,根據 ECMA-262 規則運算式方言。此物件的每個屬性值都必須為有效的 JSON 綱要。

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

此關鍵字的註解結果是此關鍵字比對到的實例屬性名稱的集合。此註解會影響此詞彙中的「additionalProperties」以及「未評估」詞彙中的「unevaluatedProperties」的行為。

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

10.3.2.3. additionalProperties

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

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

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

此關鍵字的註解結果是由此關鍵字的子綱要驗證的實例屬性名稱集合。此註解會影響「未評估」詞彙中「unevaluatedProperties」的行為。

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

實作可以選擇以其他方式實作或最佳化此關鍵字,只要產生相同的效果即可,例如直接針對實例屬性集檢查「properties」中的名稱和「patternProperties」中的模式。不支援註解收集的實作必須執行此操作。在定義此選項時,輸出格式似乎存在潛在的模糊性。模糊性不影響驗證結果,但會影響產生的輸出格式。模糊性允許多個有效的輸出結果,具體取決於是否使用註解,或使用與草案 07「產生相同效果」的解決方案。可以理解的是,來自失敗綱要的註解會被丟棄。有關詳細資訊,請參閱我們的[決策記錄](https://github.com/json-schema-org/json-schema-spec/tree/HEAD/adr/2022-04-08-cref-for-ambiguity-and-fix-later-gh-spec-issue-1172.md)。

10.3.2.4. propertyNames

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

如果實例是物件,則如果實例中的每個屬性名稱都針對提供的綱要驗證成功,則此關鍵字會驗證成功。請注意,綱要正在測試的屬性名稱永遠是字串。

省略此關鍵字的效果與空綱要相同。

11. 未評估位置的詞彙表

這些關鍵字的目的,是使綱要作者能夠將子綱要應用於,尚未針對任何相鄰關鍵字的任何動態範圍子綱要成功評估的陣列項目或物件屬性。

這些實例項目或屬性可能已經針對一個或多個相鄰的關鍵字子綱要進行了不成功的評估,例如當「anyOf」分支中的斷言失敗時。此類失敗的評估,不被視為對項目或屬性是否已評估做出貢獻。只考慮成功的評估。

如果陣列中的項目或物件屬性被「成功評估」,則在預期的物件或陣列表示中,邏輯上會被視為有效。例如,如果子綱要表示一輛車,需要 2-4 個輪子,且「wheels」的值為 6,則實例物件不會被「評估」為汽車,「wheels」屬性被視為「未評估(作為已知事物成功評估)」,且不保留任何註解。

請回想一下,相鄰的關鍵字是同一個綱要物件中的關鍵字,而動態範圍子綱要則包含參考目標以及詞彙子綱要。

這些關鍵字的行為取決於,適用於正在驗證的實例位置的相鄰關鍵字的註解結果。

不使用「$vocabulary」的元綱要,應被視為要求此詞彙表,如同其 URI 存在且值為 true 一樣。

此詞彙表目前的 URI,稱為未評估應用程式詞彙表,為:<https://json-schema.dev.org.tw/draft/2020-12/vocab/unevaluated>。

相應元綱要的目前 URI 為:https://json-schema.dev.org.tw/draft/2020-12/meta/unevaluated

11.1. 關鍵字獨立性

綱要關鍵字通常獨立運作,不會影響彼此的結果。然而,此詞彙表中的關鍵字是顯著的例外:

11.2. unevaluatedItems

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

此關鍵字的行為,取決於適用於正在驗證的實例位置的相鄰關鍵字的註解結果。具體來說,來自「prefixItems」、「items」和「contains」的註解,這些註解可能來自與「unevaluatedItems」關鍵字相鄰時的關鍵字。這三個註解以及「unevaluatedItems」,也可能來自任何和所有相鄰的就地應用程式第 10.2 節關鍵字。這包括但不限於本文檔中定義的就地應用程式。

如果沒有相關的註解,則「unevaluatedItems」子綱要必須應用於陣列中的所有位置。如果任何相關的註解中存在布林值 true,則必須忽略「unevaluatedItems」。否則,子綱要必須應用於大於「prefixItems」的最大註解值的任何索引,該索引不會出現在「contains」的任何註解值中。

這表示「prefixItems」、「items」、「contains」和所有就地應用程式,必須在此關鍵字評估之前進行評估。擴充關鍵字的作者,不得定義需要在此關鍵字評估後進行評估的就地應用程式。

如果「unevaluatedItems」子綱要應用於實例陣列中的任何位置,則會產生布林值 true 的註解結果,類似於「items」的行為。此註解會影響父綱要中「unevaluatedItems」的行為。

省略此關鍵字的效果,與空綱要的斷言行為相同。

11.3. unevaluatedProperties

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

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

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

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

這表示「properties」、「patternProperties」、「additionalProperties」和所有就地應用程式,必須在此關鍵字評估之前進行評估。擴充關鍵字的作者,不得定義需要在此關鍵字評估後進行評估的就地應用程式。

此關鍵字的註解結果,是此關鍵字的子綱要所驗證的實例屬性名稱的集合。此註解會影響父綱要中「unevaluatedProperties」的行為。

省略此關鍵字的效果,與空綱要的斷言行為相同。

12. 輸出格式化

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

12.1. 格式

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

12.2. 輸出格式

此規格定義了四種輸出格式。有關每種格式的要求,請參閱「輸出結構」一節。

  • 旗標 - 一個布林值,僅表示整體驗證結果,沒有其他詳細資訊。
  • 基本 - 在平面清單結構中提供驗證資訊。
  • 詳細 - 根據綱要的結構,在簡潔的階層結構中提供驗證資訊。
  • 詳細 - 在與綱要的確切結構相符的非簡潔階層結構中提供驗證資訊。

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

12.3. 最低資訊

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

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

實作可以選擇提供額外的資訊。

12.3.1. 關鍵字相對位置

驗證路徑之後的驗證關鍵字的相對位置。該值必須表示為 JSON 指標,並且必須包含任何以引用方式進行的應用程式,例如 "$ref" 或 "$dynamicRef"。

/properties/width/$ref/minimum

請注意,由於包含這些以引用方式進行的應用程式關鍵字,此指標可能無法透過正常的 JSON 指標程序解析。

此資訊的 JSON 鍵為 "keywordLocation"。

12.3.2. 關鍵字絕對位置

驗證關鍵字的絕對、已取消參考的位置。該值必須表示為完整的 URI,使用相關的綱要資源的規範 URI 和 JSON 指標片段,並且不得包含以引用方式進行的應用程式,例如 "$ref" 或 "$dynamicRef" 作為非終端路徑組件。 如果錯誤或註解是針對該關鍵字(例如無法解析的引用),則可以以這些關鍵字結尾。 請注意,此處的「絕對」是指「絕對檔案系統路徑」的意義(表示完整的位置),而不是 RFC 3986 中的「absolute-URI」術語(表示具有 scheme 但不帶片段)。 關鍵字的絕對位置將具有片段,以識別關鍵字。

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

僅當動態範圍未傳遞引用,或者綱要未將絕對 URI 宣告為其 "$id" 時,才可以省略此資訊。

此資訊的 JSON 鍵為 "absoluteKeywordLocation"。

12.3.3. 實例位置

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

此資訊的 JSON 鍵為 "instanceLocation"。

12.3.4. 錯誤或註解

驗證產生的錯誤或註解。

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

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

失敗驗證的 JSON 鍵為 "error";對於成功驗證,則為 "annotation"。

12.3.5. 巢狀結果

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

失敗驗證中巢狀結果的 JSON 鍵為 "errors";對於成功驗證,則為 "annotations"。 請注意複數形式,因為具有巢狀結果的關鍵字也可能具有本機錯誤或註解。

12.4. 輸出結構

輸出必須是一個包含名為 "valid" 的布林屬性的物件。 當需要有關結果的其他資訊時,輸出也必須包含如下所述的 "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
  }
]

此實例將無法通過驗證並產生錯誤,但是很容易推斷出產生註解的通過綱要的範例。

具體而言,它將產生的錯誤為:

  • 第二個物件缺少 "y" 屬性。
  • 第二個物件具有不允許的 "z" 屬性。
  • 只有兩個物件,但是需要三個。

請注意,這些範例中描述的錯誤訊息措辭不是此規範的要求。 實作應製作針對其受眾量身定制的錯誤訊息,或提供允許其使用者製作自己的訊息的範本機制。

12.4.1. 旗標

在最簡單的情況下,僅需要滿足 "valid" 有效屬性的布林結果。

{
  "valid": false
}

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

12.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"
    }
  ]
}

12.4.3. 詳細

「詳細」結構基於綱要,對於人類和機器而言都更具可讀性。 以這種方式組織結構使得錯誤之間的關聯更加明顯。 例如,「基本」結構中無法立即顯現缺少 "y" 屬性和額外的 "z" 屬性都源自實例中的相同位置。 在階層結構中,關聯更容易識別。

以下規則控制結果物件的建構:

  • 所有應用程式關鍵字("*Of"、"$ref"、"if"/"then"/"else" 等)都需要一個節點。
  • 沒有子系的節點會被刪除。
  • 具有單個子系的節點會被子系取代。

分支節點不需要錯誤訊息或註解。

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

12.4.4. 詳細

「詳細」結構是一個完全實現的階層結構,與綱要的階層結構完全匹配。 此結構在表單生成和驗證中具有應用,在這些應用中,錯誤的位置非常重要。

此結構與「詳細」結構之間的主要區別在於傳回所有結果。 這包括其他情況下會被刪除的子綱要驗證結果(例如,失敗驗證的註解、`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."
        }
      ]
    }
  ]
}

12.4.5. 輸出驗證綱要

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

13. 安全性考量

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

實例和綱要通常都是由不受信任的協力廠商撰寫,並部署在公共網際網路伺服器上。 驗證器應注意解析和驗證綱要是否不會消耗過多的系統資源。 驗證器不得陷入無限迴圈。

惡意方可能會導致實作重複收集大型值的副本作為註解。 在這種情況下,實作應防範過度消耗系統資源。

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

個別的 JSON 綱要詞彙也可能會具有其自己的安全性考量。 請查閱個別規格以取得更多資訊。

綱要作者應注意 "$comment" 內容,因為惡意實作可能會違反規範將其顯示給最終使用者,或者如果預期此行為,則無法將其剝離。

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

14. IANA 考量

14.1. application/schema+json

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

14.2. application/schema-instance+json

針對需要 JSON Schema 特定媒體類型的 JSON Schema 實例,建議的 MIME 媒體類型定義如下:

15. 參考文獻

15.1. 規範性參考文獻

[RFC2119]
Bradner, S.,《在 RFC 中用來表示需求層級的關鍵字》,BCP 14RFC 2119DOI 10.17487/RFC2119<https://www.rfc-editor.org/info/rfc2119>
[RFC3986]
Berners-Lee, T.Fielding, R.L. Masinter,《統一資源識別碼 (URI):通用語法》,STD 66RFC 3986DOI 10.17487/RFC3986<https://www.rfc-editor.org/info/rfc3986>
[RFC6839]
Hansen, T.A. Melnikov,《額外的媒體類型結構化語法後綴》,RFC 6839DOI 10.17487/RFC6839<https://www.rfc-editor.org/info/rfc6839>
[RFC6901]
Bryan, P., Ed.Zyp, K.M. Nottingham, Ed.,《JavaScript 物件表示法 (JSON) 指標》,RFC 6901DOI 10.17487/RFC6901<https://www.rfc-editor.org/info/rfc6901>
[RFC8259]
Bray, T., Ed.,《JavaScript 物件表示法 (JSON) 資料交換格式》,STD 90RFC 8259DOI 10.17487/RFC8259<https://www.rfc-editor.org/info/rfc8259>
[W3C.REC-ldp-20150226]
Speicher, S.Arwe, J.A. Malhotra,《連結資料平台 1.0》,全球資訊網協會建議 REC-ldp-20150226<https://www.w3.org/TR/2015/REC-ldp-20150226>
[ecma262]
「ECMA-262,第 11 版規格」<https://www.ecma-international.org/ecma-262/11.0/index.html>

15.2. 參考性參考文獻

[RFC6596]
Ohye, M.J. Kupke,《標準連結關係》,RFC 6596DOI 10.17487/RFC6596<https://www.rfc-editor.org/info/rfc6596>
[RFC7049]
Bormann, C.P. Hoffman,《簡潔二進位物件表示法 (CBOR)》,RFC 7049DOI 10.17487/RFC7049<https://www.rfc-editor.org/info/rfc7049>
[RFC7231]
Fielding, R., Ed.J. Reschke, Ed.,《超文本傳輸協定 (HTTP/1.1):語意與內容》,RFC 7231DOI 10.17487/RFC7231<https://www.rfc-editor.org/info/rfc7231>
[RFC8288]
Nottingham, M.,《Web 連結》,RFC 8288DOI 10.17487/RFC8288<https://www.rfc-editor.org/info/rfc8288>
[W3C.WD-fragid-best-practices-20121025]
Tennison, J.,《片段識別碼和媒體類型定義的最佳實務》,全球資訊網協會 WD WD-fragid-best-practices-20121025<https://www.w3.org/TR/2012/WD-fragid-best-practices-20121025>
[json-schema-validation]
Wright, A.Andrews, H.B. Hutton,《JSON Schema 驗證:JSON 結構驗證的詞彙》,工作中Internet-Draft,draft-bhutton-json-schema-validation-01<https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-01>
[json-hyper-schema]
Andrews, H.A. Wright,《JSON Hyper-Schema:JSON 超媒體註釋的詞彙》,工作中Internet-Draft,draft-handrews-json-schema-hyperschema-02<https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-hyperschema-02>
[xml-names]
Bray, T., Ed.Hollander, D., Ed.Layman, A., Ed.R. Tobin, Ed.,《XML 1.1 中的命名空間 (第二版)》,<http://www.w3.org/TR/2006/REC-xml-names11-20060816>

附錄 A. Schema 識別範例

考慮以下 schema,其中顯示 "$id" 用於識別根 schema 和各種子 schema,而 "$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 節9.2.1 節,以下 URI 編碼的JSON 指標 [RFC6901](相對於根 schema)中的 schema 具有以下基本 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

注意:URI 的片段部分不會使其成為標準或非標準,而是所使用的基本 URI(作為完整 URI 的一部分,包含任何片段)決定了最終完整 URI 的標準性質。多個「標準」URI?我們知道這可能令人困惑,並建議您閱讀位於JSON 指標片段和嵌入式 schema 資源第 9.2.1 節中的 CREF,以取得進一步評論。

附錄 B. 操作 schema 文件和參考

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

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

一組打算一起使用的 schema 資源可以使用各自的 schema 文件、全部在同一個 schema 文件中,或介於兩者之間的任何文件分組粒度來組織。

存在許多工具可以執行各種參考移除。這種情況的常見情況是產生一個單一檔案,其中所有參考都可以在該檔案內解析。通常這樣做是為了簡化散佈,或簡化程式碼,以便 JSON Schema 程式庫的各種叫用不必追蹤和載入大量的資源。

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

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

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

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

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

附錄 C. 遞迴 schema 擴充範例

考慮以下兩個 schema,描述簡單的遞迴樹狀結構,其中樹狀結構中的每個節點都可以具有任何類型的「data」欄位。第一個 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 } ]
}

當我們載入這兩個綱要時,會注意到每個綱要中都存在名為「node」的「$dynamicAnchor」(請注意,這裡沒有「#」,因為這只是一個名稱),這會產生以下完整的綱要 URI:

此外,JSON Schema 實作會追蹤這些片段是使用「$dynamicAnchor」建立的事實。

如果我們將「strict-tree」綱要應用於實例,我們會追蹤「$ref」到「tree」綱要,檢查其「children」子綱要,並在其「items」子綱要中找到「$dynamicRef」: to 「#node」(請注意 URI 片段語法的「#」)。該參考解析為「https://example.com/tree#node」,這是一個使用「$dynamicAnchor」建立的 URI 片段。因此,我們必須在追蹤參考之前檢查動態範圍。

此時,動態路徑為「#/$ref/properties/children/items/$dynamicRef」,動態範圍包含(從最外層範圍到最內層範圍):

  1. 「https://example.com/strict-tree#」
  2. 「https://example.com/tree#」
  3. 「https://example.com/tree#/properties/children」
  4. 「https://example.com/tree#/properties/children/items」

由於我們正在尋找一個可以在綱要資源內任何位置定義的純名稱片段,因此 JSON 指標片段與此檢查無關。這表示我們可以移除這些片段並消除連續重複項,產生:

  1. 「https://example.com/strict-tree」
  2. 「https://example.com/tree」

在這種情況下,最外層的資源也具有由「$dynamicAnchor」定義的「node」片段。因此,我們不是將「$dynamicRef」解析為「https://example.com/tree#node」,而是將其解析為「https://example.com/strict-tree#node」。

這樣,「tree」綱要中的遞迴會遞迴到「strict-tree」的根,而不是僅將「strict-tree」應用於實例根,而是將「tree」應用於實例子項。

此範例顯示每個綱要中相同位置的「$dynamicAnchor」,特別是資源根綱要。由於純名稱片段獨立於 JSON 結構,如果一個或兩個節點綱要物件移至「$defs」下,這也同樣有效。是匹配的「$dynamicAnchor」值告訴我們如何解析動態參考,而不是 JSON 結構中的任何相關性。

附錄 D. 使用詞彙表

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

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

詞彙表可以彼此建構,例如透過定義其關鍵字相對於另一個詞彙表的關鍵字的行為,或透過使用具有限制或擴展的可接受值集合的另一個詞彙表的關鍵字。並非所有此類詞彙表重複使用都會產生與其所建構的詞彙表相容的新詞彙表。詞彙表作者應清楚地記錄預期的任何相容性程度。

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

詞彙表作者應提供一個元綱要,該元綱要會驗證詞彙表關鍵字本身預期的用法。此類元綱要不應禁止額外的關鍵字,並且不得禁止核心詞彙表中的任何關鍵字。

建議元綱要作者使用 「allOf」第 10.2.1.1 節 關鍵字參考每個詞彙表的元綱要,儘管其他建構元綱要的機制可能適用於某些使用案例。

元綱要的遞迴性質使得「$dynamicAnchor」和「$dynamicRef」關鍵字對於擴展現有的元綱要特別有用,這可以在擴展驗證元綱要的 JSON 超綱要元綱要中看到。

除了宣告的詞彙表相關聯的元綱要描述的內容之外,元綱要可能會施加額外的限制,包括描述任何詞彙表中不存在的關鍵字。這允許將使用限制為詞彙表的子集,並驗證不打算重複使用的本機定義的關鍵字。

但是,元綱要不應與它們宣告的任何詞彙表相矛盾,例如透過要求與詞彙表預期的不同的 JSON 類型。產生的行為未定義。

打算在本機使用的元綱要,無需在任意實作中測試詞彙表支援,可以安全地完全省略「$vocabulary」。

D.2. 包含詞彙表宣告的元綱表示例

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

主要的範例元綱要也透過禁止以「unevaluated」為首碼的關鍵字來限制未評估詞彙表的使用,這些關鍵字特別難以實作。這不會變更其他詞彙表定義的語義或關鍵字集。它只是確保使用此元綱要且嘗試使用以「unevaluated」為首碼的關鍵字的綱要將無法根據此元綱要進行驗證。

最後,此元綱要描述了一個關鍵字「localKeyword」的語法,該關鍵字不屬於任何詞彙表。據推測,此元綱要的實作人員和使用者將了解「localKeyword」的語義。JSON 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"
    }
  }
}

此元綱要僅描述單一擴充詞彙表。

{
  "$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",
    }
  }
}

如上所示,即使在一般用途的元綱要的「allOf」中參考的每個單一詞彙表元綱要都宣告了其對應的詞彙表,此新元綱要也必須重新宣告它們。

結合核心和驗證規格定義的所有詞彙表,以及結合這些規格和超綱要規格定義的所有詞彙表的標準元綱要,示範了額外的複雜組合。這些元綱要的 URI 分別可以在驗證和超綱要規格中找到。

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

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

雖然預期參考的存在對於驗證結果是透明的,但程式碼產生器和 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」屬性則沒有。它只是一個具有子欄位的欄位,而不是不同類別的實例。

此使用方式要求註釋與參考位於同一個物件中,該物件必須可識別為參考。

附錄 F. 致謝

感謝 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 對該文件所做的提交和修補程式。

附錄 G. 變更日誌

本節將在離開 Internet-Draft 狀態之前刪除。

draft-bhutton-json-schema-01
  • 改進並釐清「type」、「contains」、「unevaluatedProperties」和「unevaluatedItems」關鍵字說明
  • 釐清「正規 URI」的各個方面
  • 評論關於註釋和「additionalProperties」的模糊性
  • 釐清詞彙表不需要正式定義
  • 移除對剩餘媒體類型參數的參考
  • 修正多個範例
draft-bhutton-json-schema-00
  • 嵌入式資源的「$schema」可能會變更
  • 陣列值「items」功能現在是「prefixItems」
  • 「items」取代了舊的「additionalItems」功能
  • 現在指定了「contains」註釋行為,以及「contains」和「unevaluatedItems」互動
  • 將 $recursive* 重新命名為 $dynamic*,並修改行為
  • $dynamicAnchor 定義一個像 $anchor 一樣的片段
  • $dynamic* (先前為 $recursive) 不再使用執行階段的基本 URI 判斷
  • 定義複合綱要文件(bundle)和處理方式
  • 參考 ECMA-262 第 11 版以支援正規表示式
  • 正規表示式應支援 Unicode
  • 移除媒體類型參數
  • 指定未知的關鍵字會被收集為註解
  • 將 "unevaluatedItems" 和 "unevaluatedProperties" 從核心移至它們自己的詞彙表
draft-handrews-json-schema-02
  • 更新為 RFC 8259 以符合 JSON 規範
  • 將 "definitions" 從驗證規範中移至此處作為 "$defs"
  • 將應用程式關鍵字從驗證規範中移至它們自己的詞彙表
  • 將 "dependencies" 的綱要形式從驗證規範中移為 "dependentSchemas"
  • 正式化註解收集
  • 指定建議的輸出格式
  • 根據註解和斷言結果定義關鍵字的互動方式
  • 新增 "unevaluatedProperties" 和 "unevaluatedItems"
  • 根據斷言、應用程式和註解模型定義 "$ref" 的行為
  • 允許與 "$ref" 相鄰的關鍵字
  • 注意涉及未知關鍵字的 "$ref" 目標的未定義行為
  • 新增遞迴參考,主要用於元綱要擴充
  • 新增正式詞彙的概念,以及它們如何透過元綱要被識別
  • 關於初始基本 URI 的額外指南,不限於網路檢索
  • 允許 "application/schema+json" 的 "schema" 媒體類型參數
  • 更好地解釋媒體類型參數和 HTTP Accept 標頭
  • 使用 "$id" 僅建立標準和基本絕對 URI,不包含片段
  • 將 "$id" 的純名稱片段形式替換為 "$anchor"
  • 闡明了 JSON 指標跨 "$id" 邊界的行為是不可靠的
draft-handrews-json-schema-01
  • 此草案純粹是澄清,沒有功能上的變更
  • 強調註解是 JSON 綱要的主要用途
  • 透過使用案例澄清 $id
  • 詳盡的綱要識別範例
  • 將「外部參考」替換為實作如何以及何時得知來自另一個文件的綱要
  • 將「內部參考」替換為實作如何在剖析期間識別綱要識別符號
  • 取消參考先前的「內部」或「外部」參考始終是相同的過程
  • 微小的格式改進
draft-handrews-json-schema-00
  • 使綱要關鍵字詞彙的概念更加清晰
  • 請注意,「整數」的概念來自詞彙表,而不是資料模型
  • 將關鍵字分類為斷言或註解,並描述它們的一般行為
  • 根據廣義斷言解釋布林綱要
  • 保留 "$comment" 用於關於綱要的非使用者可見的註解
  • 關於 "$id" 和片段的措辭改進
  • 請注意使用遞迴參考擴充元綱要的挑戰
  • 新增 "application/schema-instance+json" 媒體類型
  • 建議使用 "schema" 連結關係/參數,而不是 "profile"
draft-wright-json-schema-01
  • 更新簡介
  • 允許任何綱要為布林值
  • "$schema" 不應出現在子綱要中,儘管這可能會改變
  • 將 "id" 變更為 "$id";所有核心關鍵字都以 "$" 作為前綴
  • 釐清並正式化 application/schema+json 的片段
  • 請注意適用於可在 JSON 資料模型中表示的格式,例如 CBOR
draft-wright-json-schema-00
  • 更新對 JSON 的參考
  • 更新對 HTTP 的參考
  • 更新對 JSON 指標的參考
  • "id" 的行為現在根據 RFC3986 進行指定
  • 將 URI 的詞彙使用與 RFC3986 對齊
  • 移除對 draft-pbryan-zyp-json-ref-03 的參考
  • 將 "$ref" 的使用限制為預期綱要的任何地方
  • 新增「JSON 綱要資料模型」的定義
  • 新增額外的安全性考量
  • 定義用於 "id" 的子綱要識別符號的使用
  • 重寫關於 HTTP 使用的部分
  • 重寫關於使用 rel="describedBy" 和 rel="profile" 的部分
  • 修正了許多無效的範例
draft-zyp-json-schema-04
  • 從 draft v3 中拯救出來的
  • 將驗證關鍵字分割為單獨的文件
  • 將超媒體關鍵字分割為單獨的文件
  • 初始分割後草案
  • 強制使用 JSON 參考、JSON 指標
  • 定義 "id" 的角色。定義 URI 解析範圍
  • 新增互通性考量
draft-zyp-json-schema-00
  • 初始草案

作者地址

Austin Wright (編輯)
Henry Andrews (編輯)
Ben Hutton (編輯)
Postman
Greg Dennis