互联网草案 JSON 模式 2022 年 6 月
赖特等人。 于 2022 年 12 月 18 日过期 [页]
工作组
互联网工程任务组
互联网草案
draft-bhutton-json-schema-01
已发布
预期状态
信息性
过期
作者
A. 赖特,
H. 安德鲁斯,
B. 哈顿,
邮递员
G. 丹尼斯

JSON 模式:用于描述 JSON 文档的媒体类型

摘要

JSON 模式定义了媒体类型 "application/schema+json",这是一种基于 JSON 的格式,用于描述 JSON 数据的结构。JSON 模式断言 JSON 文档应该是什么样子,以及如何从 JSON 文档中提取信息,以及如何与 JSON 文档进行交互。媒体类型 "application/schema-instance+json" 为 "application/schema+json" 提供了更丰富的功能集成,超出了 "application/json" 文档所能提供的功能。

致读者

此草案的议题列表可以在 https://github.com/json-schema-org/json-schema-spec/issues 中找到。

有关更多信息,请参见 https://json-schema.fullstack.org.cn/

要提供反馈,请使用此问题跟踪器,主页上列出的通信方式,或发送电子邮件给文档编辑。

本备忘录的状态

本互联网草案完全符合 BCP 78 和 BCP 79 的规定提交。

互联网草案是互联网工程任务组 (IETF) 的工作文档。请注意,其他团体也可能以互联网草案的形式分发工作文档。当前互联网草案的列表在 https://datatracker.ietf.org/drafts/current/

互联网草案是有效期最长为六个月的草案文档,并且可能会随时更新、替换或被其他文档取代。将互联网草案用作参考材料或引用它们(除了作为“正在进行中的工作”以外)是不合适的。

本互联网草案将于 2022 年 12 月 18 日过期。

目录

1. 简介

JSON Schema 是一种用于定义 JSON 数据结构的 JSON 媒体类型。JSON Schema 用于定义 JSON 数据的验证、文档、超链接导航和交互控制。

本规范定义了 JSON Schema 的核心术语和机制,包括通过引用指向另一个 JSON Schema、取消引用 JSON Schema 引用、指定使用的方言、指定方言的词汇表要求以及定义预期的输出。

其他规范定义了用于对验证、链接、注释、导航和交互进行断言的词汇表。

2. 约定和术语

本文件中使用的关键术语“必须”、“不得”、“必需”、“应”、“不应”、“建议”、“不建议”、“可选”的解释如 RFC 2119 [RFC2119] 中所述。

本文件中使用的术语“JSON”、“JSON 文本”、“JSON 值”、“成员”、“元素”、“对象”、“数组”、“数字”、“字符串”、“布尔值”、“真”、“假”和“空值”的解释如 RFC 8259 [RFC8259] 中所述。

3. 概述

本文档提出了一种新的媒体类型“application/schema+json”,用于标识用于描述 JSON 数据的 JSON Schema。它还提出了一种可选的媒体类型“application/schema-instance+json”,以提供额外的集成功能。JSON Schema 本身就是 JSON 文档。本规范及其相关规范定义了关键字,允许作者以多种方式描述 JSON 数据。

JSON Schema 使用关键字来断言对 JSON 实例的约束或用附加信息来注释这些实例。其他关键字用于将断言和注释应用于更复杂的 JSON 数据结构,或者基于某种条件。

为了便于重用,关键字可以组织成词汇表。词汇表包含关键字列表及其在元模式中标识的语法和语义。方言定义为一组词汇表及其在元模式中标识的必需支持。

JSON Schema 可以通过定义附加词汇表或非正式地通过在任何词汇表之外定义附加关键字来扩展。未识别的单个关键字只是将其值收集为注释,而关于未识别词汇表的行为可以在声明使用哪些词汇表时控制。

本文档定义了一个核心词汇表,任何实现都必须支持,并且无法禁用。其关键字都以“$”字符为前缀,以强调其必需的性质。该词汇表对于“application/schema+json”媒体类型的正常运行至关重要,并用于引导加载其他词汇表。

此外,本文档定义了一个推荐的词汇表,用于有条件地应用子模式,以及将子模式应用于对象和数组的内容。无论这些模式是用于断言验证、注释还是两者兼而有之,都需要该词汇表或非常类似的词汇表来编写非平凡 JSON 实例的模式。虽然不是必需的核心词汇表的一部分,但为了实现最大的互操作性,本文档中包含了该附加词汇表,强烈建议使用它。

其他文档定义了用于结构验证或超媒体注释等目的的进一步词汇表。这些其他文档每个都定义了一个方言,收集编写用于该文档目的的模式所需的标准词汇表集。

4. 定义

4.1. JSON 文档

JSON 文档是由 application/json 媒体类型描述的信息资源(一系列八位字节)。

在 JSON Schema 中,由于它定义的数据模型,“JSON 文档”、“JSON 文本”和“JSON 值”这些术语可以互换使用。

JSON Schema 仅在 JSON 文档上定义。但是,任何可以根据 JSON Schema 数据模型解析或处理的文档或内存结构都可以解释为针对 JSON Schema,包括 CBOR [RFC7049] 等媒体类型。

4.2. 实例

应用模式的 JSON 文档称为“实例”。

JSON Schema 在“application/json”或兼容文档上定义,包括具有“+json”结构化语法后缀的媒体类型。

其中,本规范定义了“application/schema-instance+json”媒体类型,它定义了对 URI 中片段的处理。

4.2.1. 实例数据模型

JSON Schema 根据数据模型解释文档。根据此数据模型解释的 JSON 值称为“实例”。

实例具有六种基本类型之一,以及取决于类型的各种可能值:

空值
JSON“空值”
布尔值
“真”或“假”值,来自 JSON“真”或“假”值
对象
将字符串映射到实例的无序属性集,来自 JSON“对象”值
数组
实例的有序列表,来自 JSON“数组”值
数字
任意精度的基数为 10 的十进制数字值,来自 JSON“数字”值
字符串
Unicode 码点的字符串,来自 JSON“字符串”值

空白和格式问题,包括在数据模型中相等但数字的词汇表示形式不同,因此不在 JSON Schema 的范围之内。 JSON Schema 词汇表 (第 8.1 节) 想要处理这种词汇表示形式上的差异,应该定义关键字来精确解释数据模型中的格式化字符串,而不是依赖于原始 JSON 表示的 Unicode 字符可用。

由于一个对象不能有两个具有相同键的属性,因此对于尝试在一个对象中定义两个具有相同键的属性的 JSON 文档的行为是未定义的。

请注意,JSON Schema 词汇表可以自由定义自己的扩展类型系统。这不应该与这里定义的核心数据模型类型混淆。例如,“整数”是词汇表定义为关键字值的合理类型,但数据模型不区分整数和其他数字。

4.2.2. 实例相等性

如果且仅当两个 JSON 实例的类型相同且根据数据模型具有相同的值时,它们被称为相等。具体来说,这意味着:

  • 两者都是空值;或者
  • 两者都是真值;或者
  • 两者都是假值;或者
  • 两者都是字符串,并且码点与码点相同;或者
  • 两者都是数字,并且具有相同的数学值;或者
  • 两者都是数组,并且每项按项相等;或者
  • 两者都是对象,并且其中一个对象中的每个属性在另一个对象中恰好有一个属性,其键等于另一个对象的键,并且另一个属性具有相等的值。

这个定义隐含着数组必须具有相同的长度,对象必须具有相同的成员数量,对象中的属性是无序的,没有办法定义两个具有相同键的属性,并且仅仅是格式差异(缩进、逗号的位置、尾随零)无关紧要。

4.2.3. 非 JSON 实例

可以使用 JSON Schema 来处理 JSON Schema 数据模型的超集,其中实例可能不在六种 JSON 数据类型中的任何一种。

在这种情况下,注释仍然适用;但大多数验证关键字将没有用,因为它们总是通过或总是失败。

自定义词汇表可以定义对核心数据模型超集的支持。模式本身可能只能在此超集中表达;例如,为了使用“const”关键字。

4.3. JSON Schema 文档

JSON Schema 文档,或简称为模式,是一个 JSON 文档,用于描述一个实例。模式本身可以被解释为一个实例,但 SHOULD 始终使用媒体类型 "application/schema+json" 而不是 "application/schema-instance+json"。 "application/schema+json" 媒体类型被定义为提供 "application/schema-instance+json" 提供的片段标识符语法和语义的超集。

JSON Schema MUST 是一个对象或一个布尔值。

4.3.1. JSON Schema 对象和关键字

应用于实例的对象属性称为关键字或模式关键字。从广义上讲,关键字可以分为五类之一:

标识符
通过设置模式的 URI 和/或更改基 URI 的确定方式来控制模式标识
断言
当应用于实例时产生布尔结果
注释
将信息附加到实例供应用程序使用
应用器
将一个或多个子模式应用于实例中的特定位置,并组合或修改其结果
保留位置
不会直接影响结果,但为特定目的保留一个位置以确保互操作性

关键字可能属于多个类别,但应用器 SHOULD 仅基于其子模式的结果产生断言结果。它们不应该定义独立于其子模式的额外约束。

同一个模式对象中的属性称为相邻关键字。

扩展关键字,即在本规范及其配套文件中定义的那些关键字,可以自由地定义其他行为。

JSON Schema MAY 包含不是模式关键字的属性。未知关键字 SHOULD 被视为注释,其中关键字的值是注释的值。

空模式是一个 JSON Schema,它没有属性,或者只有未知属性。

4.3.2. 布尔 JSON 模式

布尔模式值 "true" 和 "false" 是简单的模式,它们始终产生自身作为断言结果,无论实例值如何。它们永远不会产生注释结果。

这些布尔模式存在是为了澄清模式作者的意图并促进模式处理优化。它们的行為与以下模式对象相同(其中 "not" 是在本规范中定义的子模式应用词汇的一部分)。

true
始终通过验证,就像空模式 {} 一样
false
始终验证失败,就像模式 { "not": {} } 一样

虽然空模式对象是明确的,但 "false" 模式有许多可能的等价物。使用布尔值确保意图对人类读者和实现都清晰。

4.3.3. 模式词汇表

模式词汇表,或简称为词汇表,是一组关键字、它们的语法和语义。词汇表通常围绕特定目的进行组织。JSON Schema 的不同用途,例如验证、超媒体或用户界面生成,将涉及不同的词汇表集。

词汇表是 JSON Schema 中重新使用的主要单位,因为模式作者可以指示哪些词汇表是必需的或可选的才能处理模式。由于词汇表在元模式中通过 URI 标识,因此通用实现可以加载扩展以支持以前未知的词汇表。虽然可以在任何词汇表之外支持关键字,但没有类似的机制来指示单个关键字的使用。

模式词汇表可以通过从非正式描述到标准建议的任何东西来定义,具体取决于受众和互操作性期望。特别是,为了便于在非公共组织内使用词汇表,词汇表规范不需要在其使用范围之外发布。

4.3.4. 元模式

本身描述模式的模式称为元模式。元模式用于验证 JSON Schema 并指定它们正在使用哪些词汇表。

通常,元模式将指定一组词汇表,并验证符合这些词汇表语法的模式。但是,元模式和词汇表是分开的,以允许元模式更严格或更宽松地验证模式一致性,而不是词汇表规范所要求的。元模式还可以描述和验证不是正式词汇表一部分的其他关键字。

4.3.5. 根模式和子模式以及资源

JSON Schema 资源是指通过 规范化 [RFC6596]绝对 URI [RFC3986] 标识的模式。模式资源 MAY 也通过 URI 标识,包括包含片段的 URI,如果生成的次级资源(如 RFC 3986 的第 3.5 节 [RFC3986] 中定义的)与主资源相同。这可能发生在使用空片段时,或者当一个模式资源嵌入在另一个模式资源中时。任何包含片段的此类 URI 被认为是非规范化的。

根模式是指构成所讨论的整个 JSON 文档的模式。根模式始终是一个模式资源,其中 URI 是根据第 9.1.1 节中描述的方式确定的。 请注意,以另一种格式嵌入模式的文档在这种意义上将不会具有根模式资源。此类用法如何与 JSON Schema 文档和资源概念相吻合将在未来草案中阐明。

某些关键字使用模式本身,允许 JSON Schema 嵌套:

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

在本示例文档中,标题为 "array item" 的模式是一个子模式,标题为 "root" 的模式是根模式。

与根模式一样,子模式要么是一个对象,要么是一个布尔值。

如第 8.2.1 节所述,JSON Schema 文档可以包含多个 JSON Schema 资源。在没有限定词的情况下使用时,术语 "根模式" 指的是文档的根模式。在某些情况下,会讨论资源根模式。资源的根模式是其顶层模式对象,如果资源要被提取到独立的 JSON Schema 文档中,它也将是一个文档根模式。

无论多个模式资源是嵌入还是通过引用链接,它们的处理方式相同,可用的行为也相同。

5. 片段标识符

根据 RFC 6839 [RFC6839] 的第 3.1 节,为任何 +json 媒体类型指定的片段标识符语法和语义 SHOULD 与 "application/json" 中指定的相同。(在本规范发布时,"application/json" 没有定义片段标识语法。)

此外,"application/schema+json" 媒体类型支持两种片段标识符结构:普通名称和 JSON 指针。"application/schema-instance+json" 媒体类型支持一种片段标识符结构:JSON 指针。

JSON 指针作为 URI 片段标识符的使用在 RFC 6901 [RFC6901] 中描述。对于支持两种片段标识符语法的 "application/schema+json",匹配 JSON 指针语法的片段标识符,包括空字符串,MUST 被解释为 JSON 指针片段标识符。

根据 W3C 的 片段标识符最佳实践 [W3C.WD-fragid-best-practices-20121025],"application/schema+json" 中的普通名称片段标识符保留用于引用本地命名的模式。所有不匹配 JSON 指针语法的片段标识符 MUST 被解释为普通名称片段标识符。

在 "application/schema+json" 文档中定义和引用普通名称片段标识符在 "$anchor" 关键字 (第 8.2.2 节) 部分中指定。

6. 一般注意事项

6.1. JSON 值范围

实例可以是 JSON [RFC8259] 中定义的任何有效的 JSON 值。JSON Schema 对类型没有限制:JSON Schema 可以描述任何 JSON 值,包括例如 null。

6.2. 编程语言独立性

JSON Schema 与编程语言无关,并支持数据模型中描述的全部值范围。但是,请注意,某些语言和 JSON 解析器可能无法在内存中表示 JSON 可描述的全部值范围。

6.3. 数学整数

某些编程语言和解析器对浮点数使用不同的内部表示,而不是对整数使用不同的内部表示。

为了保持一致性,整数 JSON 数字 SHOULD NOT 编码小数部分。

6.4. 正则表达式

关键字 MAY 使用正则表达式来表达约束,或将实例值约束为正则表达式。这些正则表达式 SHOULD 符合 ECMA-262,第 21.2.1 节 [ecma262] 中描述的正则表达式方言。

正则表达式 SHOULD 使用 "u" 标志(或等效标志)构建以提供 Unicode 支持,或者以提供 ECMA-262 中定义的 Unicode 支持的方式进行处理。

此外,鉴于正则表达式构造支持存在很大差异,模式作者 SHOULD 将自己限制在以下正则表达式标记中:

  • 单个 Unicode 字符,如 JSON 规范 [RFC8259] 中所定义;
  • 简单字符类 ([abc]),范围字符类 ([a-z]);
  • 补充字符类 ([^abc],[^a-z]);
  • 简单量词:"+"(一次或多次),“*”(零次或多次),“?”(零次或一次),以及它们的懒惰版本("+?",“*?”,“??”);
  • 范围量词:“{x}”(正好 x 次出现),“{x,y}”(至少 x 次,最多 y 次出现),{x,}(x 次或更多次出现),以及它们的懒惰版本;
  • 输入开头("^")和输入结尾("$")锚点;
  • 简单分组("(...)")和交替("|")。

最后,实现**不能**将正则表达式视为锚定,无论是在开头还是在结尾。这意味着,例如,模式“es”匹配“expression”。

6.5. 扩展 JSON Schema

任何实体都可以定义额外的模式关键字和模式词汇表。除明确协议外,模式作者**不应该**期望这些额外的关键字和词汇表得到不支持此类支持的实现的支持。实现**应该**将不支持的关键字视为注释,其中关键字的值是注释的值。

实现**可以**提供注册或加载对它们不支持的词汇表的处理程序的能力。注册和实现此类处理程序的确切机制取决于实现。

7. 关键字行为

JSON Schema 关键字属于几个通用的行为类别。断言验证实例是否满足约束,产生布尔结果。注释附加应用程序可以以任何他们认为合适的方式使用的信息。应用器将子模式应用于实例的各个部分并组合其结果。

扩展关键字**应该**保留在这些类别中,牢记注释特别灵活。复杂的行为通常最好委托给基于注释数据的应用程序,而不是直接作为模式关键字实现。但是,扩展关键字**可以**为专门目的定义其他行为。

针对模式评估实例涉及对模式中的所有关键字进行处理,以针对实例中的适当位置进行处理。通常,应用器关键字被处理,直到达到没有应用器(因此没有子模式)的模式对象。实例中的适当位置根据模式对象中的断言和注释关键字进行评估,并将它们的结果根据应用器的规则收集到父模式中。

一旦所有子模式都被评估,父模式对象的评估就可以完成,尽管在某些情况下,评估可能会由于断言结果而被短路。当收集注释时,一些断言结果短路是不可能的,因为需要检查所有子模式以进行注释收集,包括那些不能进一步改变断言结果的子模式。

7.1. 词法范围和动态范围

虽然大多数 JSON Schema 关键字可以独立评估,或者最多需要考虑相同模式对象中相邻关键字的值或结果,但有一些关键字的行为更加复杂。

关键字的词法范围由对象和数组的嵌套 JSON 数据结构确定。最大的范围是整个模式文档。最小的范围是单个没有子模式的模式对象。

关键字**可以**使用部分值(例如 URI 引用)定义,该值必须针对另一个值(例如另一个 URI 引用或完整 URI)解析,该值是通过 JSON 文档的词法结构找到的。"$id"、"$ref" 和 "$dynamicRef" 核心关键字以及 "base" JSON 超模式关键字是这种行为的示例。

请注意,一些关键字,如 "$schema",适用于整个模式资源的词法范围,因此**必须**只出现在模式资源的根模式中。

其他关键字可能会考虑在评估模式期间存在的动态范围,通常与实例文档一起使用。最外部的动态范围是处理开始的模式对象,即使它不是模式资源根。从这个根模式到任何特定关键字的路径(包括可能已解析的任何 "$ref" 和 "$dynamicRef" 关键字)被认为是关键字的“验证路径”。

词法范围和动态范围对齐,直到遇到引用关键字。虽然遵循引用关键字会将处理从一个词法范围移动到另一个词法范围,但从动态范围的角度来看,遵循引用与下降到作为值的子模式没有区别。该引用远端的一个关键字通过动态范围解析信息,将考虑引用的源端是它们的动态父级,而不是检查本地词法包围的父级。

动态范围的概念主要用于 "$dynamicRef" 和 "$dynamicAnchor",应被视为高级功能,在定义其他关键字时应谨慎使用。它也出现在报告错误和收集的注释时,因为可能用不同的动态范围重复访问同一个词法范围。在这种情况下,重要的是告知用户产生错误或注释的动态路径。

7.2. 关键字交互

关键字行为**可以**根据子模式 (第 4.3.5 节)和/或相邻关键字(相同模式对象中的关键字)及其子模式的注释结果来定义。此类关键字**不能**导致循环依赖。关键字**可以**根据另一个关键字在相同模式对象 (第 4.3 节)中是否存在来修改它们的行为。

7.3. 默认行为

缺少关键字**不能**产生错误的断言结果,**不能**产生注释结果,并且**不能**导致任何其他模式作为其自身行为定义的一部分被评估。但是,鉴于缺少关键字不会贡献注释,缺乏注释结果可能会间接改变其他关键字的行为。

在某些情况下,缺少关键字断言行为与特定值产生的行为相同,关键字定义**应该**在已知的情况下记录此类值。但是,即使产生默认行为的值如果存在会产生注释结果,默认行为仍然**不能**导致注释。

由于注释收集可能会在计算和内存方面增加显着的成本,因此实现**可以**选择退出此功能。以收集的注释的形式指定的关键字**应该**在适当的情况下描述合理的其他方法。本文件中 "items" 和 "additionalProperties" 关键字展示了这种方法。

请注意,当关键字不可能使用其他方法时,不支持注释收集的实现将无法支持包含这些关键字或词汇表的那些关键字或词汇表。

7.4. 标识符

标识符定义模式的 URI,或影响在引用 (第 8.2.3 节)中如何解析这些 URI,或两者兼而有之。本文件中定义的核心词汇表定义了几个识别关键字,最值得注意的是 "$id"。

规范模式 URI**不能**在处理实例时更改,但影响 URI 引用解析的关键字**可以**具有在运行时才能完全确定的行为。

虽然自定义标识符关键字是可能的,但词汇表设计人员应注意不要破坏核心关键字的功能。例如,本规范中的 "$dynamicAnchor" 关键字将其实 URI 解析效果限制在匹配的 "$dynamicRef" 关键字上,保持 "$ref" 的行为不受影响。

7.5. 应用器

应用器允许构建比使用单个模式对象所能实现的更复杂的模式。针对模式文档 (第 4.3 节)评估实例从将根模式 (第 4.3.5 节)应用于完整的实例文档开始。从那里,称为应用器的关键字用于确定应用哪些其他模式。这些模式可以就地应用于当前位置,或应用于子位置。

要应用的模式可以作为包含关键字值全部或部分的子模式存在。或者,应用器可以引用同一模式文档中其他位置或不同模式文档中的模式。标识此类引用模式的机制由关键字定义。

应用器关键字还定义了如何修改和/或组合子模式或引用模式的布尔断言 (第 7.6 节)结果,以产生应用器的布尔结果。应用器可以对子模式的断言结果应用任何布尔逻辑运算,但**不能**引入自己的新断言条件。

注释 (第 7.7 节)结果将与实例位置和模式关键字的位置一起保留,以便应用程序可以决定如何解释多个值。

7.5.1. 被引用模式和引用模式

第 7.5 节所述,应用器关键字可以引用要应用的模式,而不是将其作为子模式包含在应用器值中。在这种情况下,被应用的模式被称为被引用模式,而包含应用器关键字的模式被称为引用模式。

虽然根模式和子模式是基于模式在模式文档中的位置的静态概念,但被引用模式和引用模式是动态的。在针对模式评估实例期间,不同的模式对可能会发现它们处于各种被引用和引用排列中。

对于一些按引用应用器,例如"$ref" (第 8.2.3.1 节),被引用模式可以通过对模式文档的词法范围进行静态分析来确定。其他应用器,例如 "$dynamicRef"(使用 "$dynamicAnchor"),可能会使用动态范围,因此只有在用实例评估模式的过程中才能解析。

7.6. 断言

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. 注解

JSON Schema 可以用信息注释实例,只要实例根据包含注解的模式对象及其所有父模式对象进行验证。信息可以是简单值,也可以根据实例内容计算得出。

注解附加到实例中的特定位置。由于许多子模式可以应用于任何单个位置,因此应用程序可能需要决定如何处理由同一模式对象中不同模式对象中的相同模式关键字附加到相同实例位置的不同注解值。

与断言结果不同,注解数据可以采用多种形式,这些形式提供给应用程序根据需要使用。JSON Schema 实现并不期望代表应用程序使用收集的信息。

除非另有说明,否则注解关键字的值是关键字的值。但是,也可能出现其他行为。例如,JSON 超级模式 [json-hyper-schema] 的 "links" 关键字是一个复杂的注解,它会生成部分基于实例数据的值。

虽然断言可以进行 "短路" 评估,但收集注解需要检查应用于实例位置的所有模式,即使它们无法更改整体断言结果。唯一的例外是,对于验证失败的模式对象的子模式,MAY 被跳过,因为不会保留失败模式的注解。

7.7.1. 收集注解

注解由明确定义注解收集行为的关键字收集。请注意,布尔模式不能生成注解,因为它们不使用关键字。

收集的注解 MUST 包含以下信息:

  • 生成注解的关键字的名称
  • 它附加到的实例位置,作为 JSON 指针
  • 模式位置路径,指示如何跟随 "$ref" 等引用关键字以到达绝对模式位置。
  • 附加关键字的绝对模式位置,作为 URI。如果与上面的模式位置路径相同,则 MAY 被省略。
  • 附加的值
7.7.1.1. 区分多个值

应用程序 MAY 基于贡献值的模式位置来决定使用哪个注解值。这旨在允许灵活的使用。收集模式位置可以促进这种使用。

例如,考虑这个模式,它使用来自验证规范 [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 断言结果的模式对象 MUST NOT 生成任何注解结果,无论来自它们自己的关键字还是来自子模式中的关键字。

请注意,总体模式结果可能仍然包括从其他模式位置收集的注解。给定此模式:

{
    "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. 加载实例数据

虽然作为本文件或相关文档的一部分定义的词汇表中没有一个定义可以定位和/或加载实例数据的关键字,但其他词汇表可能希望这样做。

MAY 定义关键字以使用 JSON 指针或相对 JSON 指针来检查当前评估位置以外的实例部分。

允许使用相对 JSON 指针调整位置的关键字 SHOULD 默认使用当前位置,如果需要默认值。

8. JSON Schema 核心词汇表

本节中声明的关键字(均以 "$" 开头)构成了 JSON Schema 核心词汇表。这些关键字对于处理任何模式或元模式都是必需的,包括跨多个文档拆分的模式或元模式,或者存在是为了保留关键字用于需要保证互操作性的目的。

为了启动进一步词汇表的处理,核心词汇表 MUST 一直被视为强制性的。使用"$vocabulary" (第 8.1 节) 关键字声明正在使用的词汇表的元模式 MUST 明确列出核心词汇表,该词汇表 MUST 具有值为 true 的值,表示它是必需的。

此词汇表(仅此词汇表)的 false 值的行为是未定义的,当 "$vocabulary" 存在但未包含核心词汇表时,行为也是未定义的。但是,RECOMMENDED 实施检测这些情况并在发生这些情况时引发错误。声明元模式可选地使用核心是没有意义的。

不使用 "$vocabulary" 的元模式 MUST 被认为需要核心词汇表,就好像它的 URI 存在且值为 true 一样。

核心词汇表的当前 URI 为:<https://json-schema.fullstack.org.cn/draft/2020-12/vocab/core>。

相应元模式的当前 URI 为:https://json-schema.fullstack.org.cn/draft/2020-12/meta/core

虽然 "$" 前缀并未正式保留用于核心词汇表,但 RECOMMENDED 扩展关键字(在词汇表中或其他地方)以非 "$" 字符开头,以避免将来可能发生的冲突。

8.1. 元模式和词汇表

元模式和词汇表这两个概念用于告知实现如何解释模式。每个模式都有一个元模式,可以使用“$schema”关键字声明。

元模式有两个目的:

声明正在使用的词汇表
当“$vocabulary”关键字出现在元模式中时,它会声明哪些词汇表可用于引用该元模式的模式。词汇表定义关键字语义及其一般语法。
描述有效的模式语法
模式必须成功地根据其元模式进行验证,该元模式限制了可用关键字的语法。所描述的语法应与声明的词汇表兼容;虽然可以描述不兼容的语法,但这样的元模式可能没有用。

元模式与词汇表分离,以便词汇表可以以不同的方式组合,并且元模式作者可以施加额外的约束,例如禁止某些关键字或执行异常严格的语法验证,这可能在开发和测试周期中完成。每个词汇表通常会标识一个仅包含该词汇表关键字的元模式。

元模式创作是 JSON 模式的高级用法,因此元模式功能的设计强调灵活性和简单性。

8.1.1. “$schema”关键字

“$schema”关键字既用作 JSON 模式方言标识符,也用作资源标识符,该资源本身是一个 JSON 模式,它描述了为该特定方言编写的有效模式集。

此关键字的值必须是 URI [RFC3986](包含一个方案),并且该 URI 必须规范化。当前模式必须根据此 URI 标识的元模式验证。

如果此 URI 标识可检索资源,则该资源应该是媒体类型“application/schema+json”。

“$schema”关键字应该在文档根模式对象中使用,并且可以在嵌入式模式资源的根模式对象中使用。它不得出现在非资源根模式对象中。如果文档根模式中不存在,则结果行为由实现定义。

此属性的值在本文件和其他文件中以及由其他方定义。

8.1.2. “$vocabulary”关键字

“$vocabulary”关键字用于元模式中,以标识该元模式所描述的模式中可用的词汇表。它还用于指示每个词汇表是必需的还是可选的,从某种意义上说,实现必须了解必需的词汇表才能成功处理模式。这些信息共同构成一种方言。实现理解的任何词汇表都必须以与词汇表中包含的语义定义一致的方式进行处理。

此关键字的值必须是一个对象。对象中的属性名称必须是 URI(包含一个方案),并且该 URI 必须规范化。每个作为属性名称出现的 URI 都标识一组特定的关键字及其语义。

URI 可以是 URL,但可检索资源的性质目前未定义,并为将来使用保留。词汇表作者可以使用词汇表规范的 URL(以人类可读的媒体类型,如 text/html 或 text/plain)作为词汇表 URI。 词汇表文档可能会在即将发布的草案中添加。目前,识别关键字集被认为足够了,因为这些信息与元模式验证一起构成了当前“词汇表”的工作方式。任何未来的词汇表文档格式都将被指定为 JSON 文档,因此在目前使用 text/html 或其他非 JSON 格式不会产生任何未来的歧义。

对象属性的值必须是布尔值。如果值为 true,则不识别该词汇表的实现必须拒绝处理声明此元模式的任何模式,使用“$schema”。如果值为 false,则不识别该词汇表的实现应该继续处理此类模式。如果实现理解该词汇表,则该值没有影响。

根据 6.5,未识别的关键字应该被视为注释。这对于由未识别词汇表定义的关键字来说仍然是这种情况。目前无法区分未识别词汇表中定义的未识别关键字和任何词汇表中都不包含的未识别关键字。

“$vocabulary”关键字应该在任何旨在用作元模式的模式文档的根模式中使用。它不得出现在子模式中。

“$vocabulary”关键字必须在不作为元模式处理的模式文档中被忽略。这允许根据其自身的元模式 M 验证元模式 M',而无需验证器了解 M 声明的词汇表。

8.1.2.1. 默认词汇表

如果“$vocabulary”不存在,实现可以根据元模式确定行为,如果它从引用模式的“$schema”关键字的 URI 值中识别出来。这是在词汇表存在之前识别行为(如超模式使用方式)的方式。

如果模式引用的元模式不被识别或不存在,则行为由实现定义。如果实现继续处理模式,它必须假设使用核心词汇表。如果实现是为特定目的构建的,那么它应该假设使用所有与该目的最相关的词汇表。

例如,作为验证器的实现应该假设使用本规范和配套验证规范中的所有词汇表。

8.1.2.2. 词汇表的不可继承性

请注意,“$vocabulary”上的处理限制意味着使用“$ref”或类似关键字引用其他元模式的元模式不会自动继承这些其他元模式的词汇表声明。所有此类声明必须在每个旨在用作元模式的模式文档的根目录中重复。这在 示例元模式 (附录 D.2) 中有所体现。 此要求允许实现为每个元模式在一个地方找到所有词汇表需求信息。由于模式的可扩展性意味着可以通过引用将更细粒度的元模式组合起来,因此要求实现预测所有可能性并在引用的元模式中搜索词汇表将过于繁重。

8.1.3. 元模式和词汇表 URI 的更新

可以在规范草案之间发布更新的词汇表和元模式 URI 以更正错误。实现应该考虑此规范草案之后和下一个草案之前发布的 URI,表示与此处列出的 URI 相同的语法和语义。

8.2. 基本 URI、锚点和反引用

为了区分广阔生态系统中的模式,模式通过 URI [RFC3986] 标识,并且可以通过指定它们的 URI 嵌入对其他模式的引用。

一些关键字可以接受一个相对 URI 引用 [RFC3986],或者一个用于构造相对 URI 引用的值。对于这些关键字,有必要建立一个基本 URI 才能解析引用。

8.2.1. “$id”关键字

“$id”关键字使用其 规范 [RFC6596] URI 标识模式资源。

请注意,此 URI 是一个标识符,不一定是网络定位器。对于可寻址网络的 URL,模式不必从其规范 URI 下载。

如果存在,此关键字的值必须是字符串,并且必须表示一个有效的 URI 引用 [RFC3986]。此 URI 引用应该规范化,并且必须解析为一个 绝对 URI [RFC3986](没有片段),或者解析为一个带有空片段的 URI。

空片段形式不推荐,仅保留用于向后兼容性,以及因为 application/schema+json 媒体类型定义,具有空片段的 URI 标识与具有相同片段删除的 URI 相同的资源。但是,由于这种等价性不是 RFC 3986 规范化过程 [RFC3986] 的一部分,因此实现者和模式作者不能依赖于通用 URI 库来理解它。

因此,“$id”不得包含非空片段,并且不应该包含空片段。无论是否存在空片段,绝对 URI 形式都必须被视为规范 URI。 目前允许空片段,因为旧的元模式在其 $id(或以前,id)中有一个空片段。未来的草案可能会完全禁止“$id”中的空片段。

绝对 URI 也作为模式资源内关键字中相对 URI 引用的基本 URI,符合 RFC 3986 第 5.1.1 节 [RFC3986] 关于嵌入在内容中的基本 URI 的规定。

子模式中“$id”的存在表明子模式构成单个模式文档中的一个独立模式资源。此外,根据 RFC 3986 第 5.1.2 节 [RFC3986] 关于封装实体的规定,如果子模式中的“$id”是一个相对 URI 引用,则解析该引用的基本 URI 是父模式资源的 URI。

如果没有父模式对象明确地将自己标识为具有“$id”的资源,则基本 URI 是整个文档的 URI,如 上一节 (第 9.1.1 节) 中所述步骤建立的那样。

8.2.1.1. 标识根模式

JSON 模式文档的根模式应该包含一个“$id”关键字,其值为 绝对 URI [RFC3986](包含一个方案,但没有片段)。

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" 关键字是一个应用器,它允许将完整的解析推迟到运行时,此时它在评估实例时每次遇到它时都会被解析。

"$dynamicAnchor" 和 "$dynamicRef" 共同实现了一种协作扩展机制,它主要在递归架构(引用自身的架构)中很有用。扩展点和运行时确定的扩展目标都由 "$dynamicAnchor" 定义,并且只有在使用 "$dynamicRef" 引用时才会在运行时表现出动态行为。

"$dynamicRef" 属性的值必须是字符串,该字符串是一个 URI 引用。针对当前 URI 基本路径进行解析,它会生成用作运行时解析起点 的 URI。此初始解析在架构加载时执行是安全的。

如果最初解析的起点 URI 包含由 "$dynamicAnchor" 关键字创建的片段,则初始 URI 必须替换为定义相同名称片段的 动态范围 (第 7.1 节) 中最外部架构资源的 URI(包括片段)。

否则,它的行为与 "$ref" 相同,不需要运行时解析。

有关使用这些关键字的完整示例,请参见附录 C 2019 年之前草案中的超架构元架构与本草案之间的区别显着地证明了这些关键字的效用。

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" 的值不应作为注释结果进行收集。

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>”模式时,它将“$anchor”值解析为相对于当前基本 URI 的片段名称,以形成“<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": { }
}

在这里我们看到,使用附加到“bar”模式资源的规范 URI 的 JSON 指针片段的“https://example.com/bar#/additionalProperties”仍然有效,而“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,因为使用它们可能会降低互操作性。 这是为了避免要求实现跟踪整个可能的基 URI 和 JSON 指针片段的堆栈,因为如果模式资源重新组织,除一个以外的所有 URI 都是脆弱的。有些人认为这很容易,因此没有必要禁止它,而另一些人则认为这会使模式识别变得复杂,应该被禁止。鼓励对该主题的反馈。经过一些讨论,我们认为我们需要删除“规范”的使用,转而讨论跨模式资源边界的引用 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。

当通过引用应用器引用的模式资源被捆绑时,**建议**将模式资源放置为包含模式根部的“$defs”对象的 value。现在嵌入式模式资源的“$defs”的 key **可以**是捆绑的模式的“$id”或某种其他形式的应用程序定义的唯一标识符(例如 UUID)。此 key 不打算在 JSON 模式中被引用,但应用程序可以使用它来帮助捆绑过程。

模式资源**可以**嵌入在“$defs”以外的位置,其中该位置被定义为模式 value。

捆绑的模式资源**不得**通过替换从中引用它的模式对象或通过将模式资源包装在其他应用器关键字中来捆绑。

为了产生相同的输出,包含模式文档中对先前外部模式资源的引用**不得**更改,并且现在解析为使用嵌入式模式资源的“$id”的模式。这种相同的输出包括验证评估以及在生成的注释或错误中使用的 URI 或路径。

虽然捆绑过程通常是创建复合模式文档的主要方法,但也有可能而且期望有些人会手动创建,可能之前没有单个模式资源独立存在。

9.3.2. 不同的和默认方言

当单个文档中存在多个模式资源时,没有定义应使用哪种方言处理的模式资源**必须**使用与封闭资源相同的方言处理。

由于任何可以引用的模式也可以嵌入,因此嵌入式模式资源**可以**使用封闭资源的“$schema”值指定不同的处理方言。

9.3.3. 验证

鉴于复合模式文档可能具有标识为使用不同方言的嵌入式资源,因此这些文档**不应**通过将元模式应用于复合模式文档作为实例来进行验证。**建议**提供替代验证过程以验证模式文档。每个模式资源**应该**单独针对其关联的元模式进行验证。 如果您知道正在验证的是模式,您可以通过使用“$id”来确定模式是复合模式文档还是不是,它在不用于文档根部时标识嵌入式资源。

在所有嵌入式资源都标识为使用相同方言的复合模式文档中,或者在其中省略“$schema”并因此默认为封闭资源的“$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.fullstack.org.cn/draft/2020-12/vocab/applicator>。

相应元模式的当前 URI 是:https://json-schema.fullstack.org.cn/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 Schema。

如果对象键是实例中的属性,则整个实例必须根据子模式进行验证。其使用取决于该属性的存在。

省略此关键字与空对象的行为相同。

10.3. 将子模式应用于子实例的关键字

这些关键字中的每一个都定义了一条规则,用于将子模式应用于子实例(特别是对象属性和数组项)并组合其结果。

10.3.1. 将子模式应用于数组的关键字

10.3.1.1. prefixItems

"prefixItems" 的值**必须**是一个非空数组,包含有效的 JSON Schema。

如果实例的每个元素都根据相同位置(如果有)的模式进行验证,则验证成功。此关键字不限制数组的长度。如果数组比此关键字的值更长,则此关键字仅验证与长度匹配的前缀。

此关键字生成一个注释值,该值是此关键字应用子模式的最大索引。如果子模式已成功应用于实例的每个索引(例如由 "items" 关键字生成),则该值**可以**是布尔值 true。此注释会影响 "items" 和 "unevaluatedItems" 的行为。

省略此关键字与空数组具有相同的断言行为。

10.3.1.2. items

"items" 的值**必须**是一个有效的 JSON Schema。

此关键字将子模式应用于实例元素的所有元素,这些元素的索引大于同一个模式对象中 "prefixItems" 数组的长度(如该 "prefixItems" 关键字的注释结果所示)。如果没有这样的注释结果,"items" 将子模式应用于所有实例数组元素。 注意,没有 "prefixItems" 的 "items" 的行为与先前草案中 "items" 的模式形式相同。当 "prefixItems" 存在时,"items" 的行为与以前的 "additionalItems" 关键字相同。

如果 "items" 子模式被应用于实例数组中的任何位置,它将生成一个布尔值 true 的注释结果,指示所有剩余的数组元素都已根据此关键字的子模式进行评估。此注释会影响 Unevaluated 词汇表中 "unevaluatedItems" 的行为。

省略此关键字与空模式具有相同的断言行为。

实现**可以**选择以其他方式实现或优化此关键字,以产生相同的效果,例如直接检查 "prefixItems" 数组的存在和大小。不支持注释收集的实现**必须**这样做。

10.3.1.3. contains

此关键字的值**必须**是一个有效的 JSON Schema。

如果数组实例的至少一个元素根据给定模式进行验证,则该实例相对于 "contains" 是有效的,除非 "minContains" 存在且值为 0,在这种情况下,数组实例**必须**被视为相对于 "contains" 关键字是有效的,即使没有一个元素根据给定模式进行验证。

此关键字生成一个注释值,该值是一个数组,包含当应用其子模式时此关键字成功验证的索引(按升序排列)。如果子模式在应用于实例的每个索引时成功验证,则该值**可以**是布尔值 "true"。如果此关键字的模式所应用的实例数组为空,则**必须**存在注释。

此注释会影响 Unevaluated 词汇表中 "unevaluatedItems" 的行为,并且**可以**也用于在 Validation 词汇表中实现 "minContains" 和 "maxContains" 关键字。

即使在找到第一个匹配项后,子模式也**必须**应用于每个数组元素,以收集供其他关键字使用的注释。这是为了确保收集所有可能的注释。

10.3.2. 将子模式应用于对象的关键字

10.3.2.1. properties

"properties" 的值**必须**是一个对象。此对象的每个值**必须**是一个有效的 JSON Schema。

如果对于在实例中以及作为此关键字值中的名称出现的每个名称,该名称的子实例都根据相应的模式成功验证,则验证成功。

此关键字的注释结果是此关键字匹配的实例属性名称集。此注释会影响 "additionalProperties"(在此词汇表中)和 Unevaluated 词汇表中 "unevaluatedProperties" 的行为。

省略此关键字与空对象具有相同的断言行为。

10.3.2.2. patternProperties

"patternProperties" 的值**必须**是一个对象。此对象的每个属性名称**应该**是根据 ECMA-262 正则表达式方言的有效正则表达式。此对象的每个属性值**必须**是一个有效的 JSON Schema。

如果对于每个与作为此关键字值中属性名称出现的任何正则表达式匹配的实例名称,该名称的子实例都根据与匹配的正则表达式对应的每个模式成功验证,则验证成功。

此关键字的注释结果是此关键字匹配的实例属性名称集。此注释会影响 "additionalProperties"(在此词汇表中)和 Unevaluated 词汇表中 "unevaluatedProperties" 的行为。

省略此关键字与空对象具有相同的断言行为。

10.3.2.3. additionalProperties

"additionalProperties" 的值**必须**是一个有效的 JSON Schema。

此关键字的行为取决于同一模式对象中 "properties" 和 "patternProperties" 的存在和注释结果。使用 "additionalProperties" 进行验证仅适用于实例名称的子值,这些名称不会出现在 "properties" 或 "patternProperties" 的任何一个注释结果中。

对于所有这样的属性,如果子实例根据 "additionalProperties" 模式进行验证,则验证成功。

此关键字的注释结果是此关键字的子模式验证的实例属性名称集。此注释会影响 Unevaluated 词汇表中 "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 Schema。

如果实例是一个对象,则此关键字验证实例中的每个属性名称是否根据提供的模式进行验证。请注意,模式正在测试的属性名称将始终是一个字符串。

省略此关键字与空模式具有相同的行为。

11. 未评估位置的词汇表

这些关键字的目的是使模式作者能够将子模式应用于尚未根据任何相邻关键字的任何动态范围子模式成功评估的数组项或对象属性。

这些实例项或属性可能已根据一个或多个相邻关键字子模式不成功地进行评估,例如,当 "anyOf" 的一个分支中的断言失败时。此类失败的评估不被视为有助于确定该项或属性是否已评估。只有成功的评估才被考虑。

如果数组中的项或对象属性被 "成功评估",则在逻辑上它被认为在预期对象或数组的表示形式方面是有效的。例如,如果子模式表示一辆汽车,它需要 2-4 个车轮,并且 "wheels" 的值为 6,则实例对象不会被 "评估" 为一辆汽车,并且 "wheels" 属性被认为是 "未评估(成功地作为已知的事物)",并且不会保留任何注释。

回想一下,相邻关键字是同一个模式对象中的关键字,动态范围子模式包括引用目标和词法子模式。

这些关键字的行为取决于应用于正在验证的实例位置的相邻关键字的注释结果。

不使用 "$vocabulary" 的元模式**应该**被认为需要此词汇表,就像其 URI 存在并且值为 true 一样。

此词汇表(称为 Unevaluated Applicator 词汇表)的当前 URI 是:<https://json-schema.fullstack.org.cn/draft/2020-12/vocab/unevaluated>。

相应元模式的当前 URI 是:https://json-schema.fullstack.org.cn/draft/2020-12/meta/unevaluated

11.1. 关键字独立性

模式关键字通常独立运行,不会影响彼此的结果。但是,此词汇表中的关键字是显著的例外:

11.2. unevaluatedItems

"unevaluatedItems" 的值**必须**是一个有效的 JSON Schema。

此关键字的行为取决于应用于正在验证的实例位置的相邻关键字的注释结果。具体来说,来自 "prefixItems"、"items" 和 "contains" 的注释,这些注释可能来自这些关键字,当它们与 "unevaluatedItems" 关键字相邻时。这三个注释,以及 "unevaluatedItems",也可以来自任何和所有相邻的 就地应用器 (第 10.2 节) 关键字。这包括但不限于本文件中定义的就地应用器。

如果没有相关的注释存在,则 "unevaluatedItems" 子模式 MUST 应用于数组中的所有位置。如果来自任何相关注释的布尔值 true 存在,则 "unevaluatedItems" MUST 被忽略。否则,子模式 MUST 应用于任何大于 "prefixItems" 的最大注释值的索引,该索引未出现在 "contains" 的任何注释值中。

这意味着 "prefixItems"、"items"、"contains" 和所有就地应用器 MUST 在此关键字可以评估之前进行评估。扩展关键字的作者 MUST NOT 定义需要在此关键字之后进行评估的就地应用器。

如果 "unevaluatedItems" 子模式应用于实例数组中的任何位置,它会生成一个布尔值 true 的注释结果,类似于 "items" 的行为。此注释会影响父模式中 "unevaluatedItems" 的行为。

省略此关键字具有与空模式相同的断言行为。

11.3. unevaluatedProperties

"unevaluatedProperties" 的值 MUST 是一个有效的 JSON Schema。

此关键字的行为取决于应用于正在验证的实例位置的相邻关键字的注释结果。具体来说,来自 "properties"、"patternProperties" 和 "additionalProperties" 的注释,这些注释可能来自这些关键字,当它们与 "unevaluatedProperties" 关键字相邻时。这三个注释,以及 "unevaluatedProperties",也可以来自任何和所有相邻的 就地应用器 (第 10.2 节) 关键字。这包括但不限于本文件中定义的就地应用器。

使用 "unevaluatedProperties" 进行的验证仅适用于实例名称的子值,这些子值未出现在应用于正在验证的实例位置的 "properties"、"patternProperties"、"additionalProperties" 或 "unevaluatedProperties" 注释结果中。¶a

对于所有这些属性,如果子实例针对 "unevaluatedProperties" 模式验证成功,则验证成功。

这意味着 "properties"、"patternProperties"、"additionalProperties" 和所有就地应用器 MUST 在此关键字可以评估之前进行评估。扩展关键字的作者 MUST NOT 定义需要在此关键字之后进行评估的就地应用器。

此关键字的注释结果是此关键字的子模式验证的实例属性名称集。此注释会影响父模式中 "unevaluatedProperties" 的行为。

省略此关键字具有与空模式相同的断言行为。

12. 输出格式

JSON Schema 被定义为平台独立的。因此,为了提高跨平台的兼容性,实现 SHOULD 符合标准的验证输出格式。本节描述消费者正确解释验证结果所需的最低要求。

12.1. 格式

JSON Schema 输出使用 JSON Schema 数据实例模型定义,如第 4.2.1 节所述。实现 MAY 偏离此模型,只要其特定的语言和平台支持,但是 RECOMMENDED 输出可以通过序列化或其他方法转换为此处定义的 JSON 格式。

12.2. 输出格式

本规范定义了四种输出格式。有关每种格式的要求,请参阅 "输出结构" 部分。

  • 标志 - 一个布尔值,它只是指示整体验证结果,没有其他详细信息。
  • 基本 - 以扁平列表结构提供验证信息。
  • 详细 - 基于模式的结构,以压缩的层次结构提供验证信息。
  • 详细 - 以与模式的精确结构相匹配的未压缩层次结构提供验证信息。

实现 SHOULD 提供至少一种 "标志"、"基本" 或 "详细" 格式,并且 MAY 提供 "详细" 格式。如果它提供了一种或多种 "详细" 或 "详细" 格式,它 MUST 也提供 "标志" 格式。实现 SHOULD 在其文档中指定它们支持的格式。

12.3. 最小信息

除了简单的 "标志" 输出之外,其他信息对于帮助调试模式或实例很有用。每个子结果 SHOULD 至少包含本节中包含的信息。

包含所有这些组件的单个对象被认为是一个输出单元。

实现 MAY 选择提供其他信息。

12.3.1. 关键字相对位置

遵循验证路径的验证关键字的相对位置。该值 MUST 表达为 JSON 指针,并且 MUST 包括任何按引用应用器,例如 "$ref" 或 "$dynamicRef"。

/properties/width/$ref/minimum

请注意,由于包含这些按引用应用器关键字,此指针可能无法通过正常的 JSON 指针过程解析。

此信息的 JSON 键是 "keywordLocation"。

12.3.2. 关键字绝对位置

验证关键字的绝对、反引用位置。该值 MUST 表达为使用相关模式资源的规范 URI 的完整 URI,带有一个 JSON 指针片段,并且 MUST 不包括按引用应用器,例如 "$ref" 或 "$dynamicRef" 作为非终端路径组件。如果错误或注释是针对该关键字的,例如无法解析的引用,它 MAY 以此类关键字结尾。 请注意,这里的 "绝对" 指的是 "绝对文件系统路径"(表示完整位置),而不是 RFC 3986 中的 "绝对 URI" 术语(表示带有方案但不带片段)。关键字绝对位置将有一个片段,以便识别关键字。

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

仅当动态范围未传递引用或模式未声明 "$id" 作为其绝对 URI 时,此信息 MAY 被省略。

此信息的 JSON 键是 "absoluteKeywordLocation"。

12.3.3. 实例位置

正在验证的实例中 JSON 值的位置。该值 MUST 表达为 JSON 指针。

此信息的 JSON 键是 "instanceLocation"。

12.3.4. 错误或注释

验证产生的错误或注释。

对于错误,本规范未定义消息的具体措辞。实现需要提供此信息。

对于注释,每个产生注释的关键字都指定其格式。默认情况下,它是关键字的值。

对于失败的验证,JSON 键是 "error";对于成功的验证,它是 "annotation"。

12.3.5. 嵌套结果

对于这两种层次结构,此属性将保存嵌套的错误和注释。

对于失败的验证中嵌套的结果,JSON 键是 "errors";对于成功的验证,它是 "annotations"。请注意复数形式,因为具有嵌套结果的关键字也可以具有本地错误或注释。

12.4. 输出结构

输出 MUST 是一个对象,其中包含一个名为 "valid" 的布尔属性。当需要有关结果的更多信息时,输出 MUST 也包含 "errors" 或 "annotations",如下所述。

  • "valid" - 一个布尔值,指示整体验证成功或失败
  • "errors" - 失败验证产生的错误或注释集合
  • "annotations" - 成功验证产生的错误或注释集合

对于这些示例,将使用以下模式和实例。

{
  "$id": "https://example.com/polygon",
  "$schema": "https://json-schema.fullstack.org.cn/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" 属性。
  • 只有两个对象,但需要三个。

请注意,这些示例中描述的错误消息措辞不是本规范的要求。实现 SHOULD 为其受众定制错误消息,或提供允许其用户定制其自身消息的模板机制。

12.4.1. 标志

在最简单的情况下,只需要满足 "valid" valid 属性的布尔结果。

{
  "valid": false
}

由于此格式不返回任何错误或注释,因此 RECOMMENDED 实现使用短路逻辑,一旦确定结果,就返回失败或成功。例如,如果 "anyOf" 关键字包含五个子模式,并且第二个子模式通过,则无需检查其他三个。逻辑可以简单地返回成功。

12.4.2. 基本

"Basic" 结构是一个输出单元的扁平列表。

{
  "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.fullstack.org.cn/draft/2020-12/output/verbose-example.

// schema
{
  "$id": "https://example.com/polygon",
  "$schema": "https://json-schema.fullstack.org.cn/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 Schema 提供用于验证实现生成的输出。其 URI 为:https://json-schema.fullstack.org.cn/draft/2020-12/output/schema.

13. 安全注意事项

模式和实例都是 JSON 值。因此,RFC 8259 [RFC8259] 中定义的所有安全注意事项都适用。

实例和模式通常由不受信任的第三方编写,并部署在公共互联网服务器上。验证器应注意,解析和根据模式进行验证不会消耗过多的系统资源。验证器**必须**不陷入无限循环。

恶意方可能导致实现反复收集非常大的值作为注释。在这种情况,实现**应**防止过度消耗系统资源。

服务器**必须**确保恶意方无法通过上传具有现有或非常相似的“$id”的模式来更改现有模式的功能。

各个 JSON Schema 词汇表也可能具有其自身的安全注意事项。有关更多信息,请参阅各自的规范。

模式作者应注意“$comment”的内容,因为恶意实现可能会违反规范将它们显示给最终用户,或者如果需要此类行为,则无法将其删除。

恶意模式作者可能会在“$comment”中放置可执行代码或其他危险材料。实现**必须**不解析或以其他方式基于“$comment”内容采取行动。

14. IANA 注意事项

14.1. application/schema+json

JSON Schema 的建议 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 结构验证的词汇表”正在进行中互联网草案,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 超级模式:用于 JSON 超媒体注释的词汇表”正在进行中互联网草案,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. 模式识别示例

考虑以下模式,该模式显示“$id”用于识别根模式和各种子模式,而“$anchor”用于定义普通名称片段标识符。

{
    "$id": "https://example.com/root.json",
    "$defs": {
        "A": { "$anchor": "foo" },
        "B": {
            "$id": "other.json",
            "$defs": {
                "X": { "$anchor": "bar" },
                "Y": {
                    "$id": "t/inner.json",
                    "$anchor": "bar"
                }
            }
        },
        "C": {
            "$id": "urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f"
        }
    }
}

以下 URI 编码的 JSON 指针 [RFC6901] (相对于根架构)处的架构具有以下基本 URI,并且可以根据上述第 5 节和第 9.2.1 节中列出的任何 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 指针片段和嵌入式架构资源 (第 9.2.1 节) 部分的 CREF 以获取更多说明。

附录 B. 操作架构文档和引用

已创建各种工具来根据引用 (“$ref”) 的出现方式和位置重新排列架构文档。本附录讨论哪些用例和操作符合本规范。

B.1. 将架构资源捆绑到单个文档中

一组旨在一起使用的架构资源可以以每个资源位于其自己的架构文档中、所有资源都位于同一个架构文档中,或两者之间的任何文档分组粒度来组织。

存在许多工具可以执行各种类型的引用移除。这的一种常见情况是生成一个所有引用都可以在该文件中解析的单个文件。这通常是为了简化分发,或为了简化编码,以便 JSON 架构库的各种调用不必跟踪和加载大量资源。

只要所有静态引用(例如,“$ref”)都使用解析为使用规范资源 URI 作为基准的 URI 的 URI 引用,并且所有架构资源在它们的根架构中都有一个绝对 URI 作为“$id”,就可以安全且可逆地执行此转换。

在满足这些条件的情况下,每个外部资源都可以复制到“$defs”下,而不会破坏资源架构对象之间的任何引用,也不会改变任何验证或注释结果。假设“$defs”下的架构名称都是唯一的(因为它们不会出现在嵌入式资源的规范 URI 中),那么这些名称不会影响行为。

B.2. 引用移除并不总是安全的

尝试移除所有引用并生成一个单个架构文档并非在所有情况下都能生成与原始形式具有相同行为的架构。

由于“$ref”现在被视为与任何其他关键字一样,其他关键字允许出现在同一个架构对象中,因此在所有情况下完全支持非递归“$ref”移除可能需要相对复杂的架构操作。本规范没有确定或提供一组安全的“$ref”移除转换,因为它们不仅取决于架构结构,还取决于预期用途。

附录 C. 递归架构扩展示例

考虑以下两个描述简单递归树结构的架构,其中树中的每个节点都可以具有任何类型的“data”字段。第一个架构允许并忽略其他实例属性。第二个架构更严格,只允许“data”和“children”属性。还显示了一个“data”拼写错误为“daat”的示例实例。

// tree schema, extensible
{
    "$schema": "https://json-schema.fullstack.org.cn/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.fullstack.org.cn/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 架构实现会跟踪这些片段是用“$dynamicAnchor”创建的事实。

如果我们将“strict-tree”架构应用于实例,我们将按照“$ref”找到“tree”架构,检查其“children”子架构,并在其“items”子架构中找到“$dynamicRef”: 到“#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 架构没有提供任何正式的命名空间系统,但也没有限制关键字名称,允许使用任意数量的命名空间方法。

词汇表可以建立在彼此之上,例如通过定义它们关键字相对于另一个词汇表中关键字的行为,或通过使用另一个词汇表中的关键字,但具有受限或扩展的一组可接受的值。并非所有这种词汇表重复使用都会导致一个与构建其的词汇表兼容的新词汇表。词汇表作者应该清楚地记录预期什么级别的兼容性(如果有)。

元架构作者不应使用“$vocabulary”来组合定义同一关键字的冲突语法或语义的多个词汇表。由于语义冲突通常无法通过架构验证检测到,因此预计实现不会检测到此类冲突。如果声明了冲突的词汇表,则产生的行为是未定义的。

词汇表作者应该提供一个元架构来验证词汇表关键字在自身上的预期用法。此类元架构不应禁止额外的关键字,并且不应禁止核心词汇表中的任何关键字。

建议元架构作者使用 "allOf" (第 10.2.1.1 节) 关键字引用每个词汇表的元架构,尽管其他构建元架构的机制可能适合某些用例。

元架构的递归性质使“$dynamicAnchor”和“$dynamicRef”关键字对于扩展现有元架构特别有用,正如在扩展验证元架构的 JSON 超级架构元架构中看到的那样。

元架构可能会施加额外的约束,包括描述除了声明的词汇表关联的元架构所描述的内容之外,还描述了在任何词汇表中都不存在的关键字。这允许将用法限制在一个词汇表的子集中,并验证用于本地定义的关键字,这些关键字不打算重复使用。

但是,元架构不应与它们声明的任何词汇表相矛盾,例如通过要求与词汇表预期的不同的 JSON 类型。产生的行为是未定义的。

用于本地使用、无需在任意实现中测试词汇表支持的元架构可以安全地完全省略“$vocabulary”。

D.2. 包含词汇表声明的示例元架构

此元架构明确声明了核心和应用程序词汇表,以及扩展词汇表,并将它们的元架构与“allOf”组合在一起。扩展词汇表的元架构(它只描述该词汇表中的关键字)显示在主示例元架构之后。

主示例元架构还通过禁止以“unevaluated”为前缀的关键字来限制对未评估词汇表的用法,这些关键字在实现方面特别复杂。这不会改变其他词汇表定义的语义或关键字集。它只是确保使用此元架构并试图使用以“unevaluated”为前缀的关键字的架构将无法通过此元架构的验证。

最后,此元模式描述了不属于任何词汇表的关键字“localKeyword”的语法。预计此元模式的实现者和使用者将理解“localKeyword”的语义。JSON Schema 未定义任何机制来表达词汇表之外的关键字语义,这使得它们不适合使用,除非在特定的环境中理解它们。

此元模式将多个词汇表结合起来以供一般使用。

{
  "$schema": "https://json-schema.fullstack.org.cn/draft/2020-12/schema",
  "$id": "https://example.com/meta/general-use-example",
  "$dynamicAnchor": "meta",
  "$vocabulary": {
    "https://json-schema.fullstack.org.cn/draft/2020-12/vocab/core": true,
    "https://json-schema.fullstack.org.cn/draft/2020-12/vocab/applicator": true,
    "https://json-schema.fullstack.org.cn/draft/2020-12/vocab/validation": true,
    "https://example.com/vocab/example-vocab": true
  },
  "allOf": [
    {"$ref": "https://json-schema.fullstack.org.cn/draft/2020-12/meta/core"},
    {"$ref": "https://json-schema.fullstack.org.cn/draft/2020-12/meta/applicator"},
    {"$ref": "https://json-schema.fullstack.org.cn/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.fullstack.org.cn/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. 更改日志

在离开互联网草案状态之前将删除此部分。

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 确定
  • 定义复合模式文档(捆绑)和处理
  • 参考 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 Schema 的主要用途
  • 通过用例澄清 $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 Schema 数据模型”的定义
  • 添加了额外的安全注意事项
  • 定义了“id”的子模式标识符的使用
  • 重写了有关使用 HTTP 的部分
  • 重写了有关使用 rel="describedBy" 和 rel="profile" 的部分
  • 修复了许多无效的示例
draft-zyp-json-schema-04
  • 从草案 v3 中抢救
  • 将验证关键字拆分为单独的文档
  • 将超媒体关键字拆分为单独的文档
  • 初始拆分后草案
  • 强制使用 JSON 参考、JSON 指针
  • 定义“id”的作用。定义 URI 解析范围
  • 添加互操作性考虑因素
draft-zyp-json-schema-00
  • 初始草案

作者地址

奥斯汀·赖特(编辑
亨利·安德鲁斯(编辑
Ben Hutton (编辑)
邮递员
Greg Dennis