互联网草案 JSON Schema 2022 年 6 月
Wright 等人 到期时间:2022 年 12 月 18 日 [页面]
工作组
互联网工程任务组
互联网草案
draft-bhutton-json-schema-01
已发布
预期状态
信息性
到期时间
作者
A. Wright,
H. Andrews,
B. Hutton,
邮递员
G. Dennis

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

摘要

JSON Schema 定义了媒体类型“application/schema+json”,这是一种基于 JSON 的格式,用于描述 JSON 数据的结构。JSON Schema 断言 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“数组”值的实例的有序列表
数字
来自 JSON“数字”值的任意精度、以 10 为基数的十进制数
字符串
来自 JSON“字符串”值的 Unicode 代码点字符串

因此,空白和格式问题(包括在数据模型中相等的数字的不同词法表示)超出了 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 文档。模式本身可以解释为实例,但始终应该使用媒体类型“application/schema+json”而不是“application/schema-instance+json”。“application/schema+json”媒体类型被定义为提供由“application/schema-instance+json”提供的片段标识符语法和语义的超集。

JSON Schema 必须是对象或布尔值。

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 模式并指定它们正在使用的词汇。

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

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

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

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

一些关键字采用模式本身,允许 JSON 模式嵌套:

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

在本示例文档中,标题为“数组项”的模式是一个子模式,标题为“根”的模式是根模式。

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

如第 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 指针。

RFC 6901 [RFC6901] 中描述了将 JSON 指针用作 URI 片段标识符。对于支持两种片段标识符语法的“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 次或更多次出现)以及它们的惰性版本;
  • 输入开头("^")和输入结尾("$")锚点;
  • 简单分组("(...)")和选择("|")。

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

6.5. 扩展 JSON Schema

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

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

7. 关键字行为

JSON 模式关键字分为几个常见的行为类别。断言验证实例是否满足约束,生成布尔结果。注释附加应用程序可以随意使用的信息。应用程序将子模式应用于实例的部分并组合其结果。

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

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

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

7.1. 词法范围和动态范围

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

关键字的词法范围由对象和数组的嵌套 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,或影响此类 URI 在引用 (第 8.2.3 节) 中的解析方式,或两者兼而有之。本文件中定义的核心词汇表定义了几个标识关键字,最显着的是 "$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 模式可用于断言 JSON 文档的约束,该文档要么通过断言,要么失败。这种方法可用于验证是否符合约束,或记录满足约束所需的条件。

JSON 模式实现根据实例对模式断言的评估生成单个布尔结果。

实例只能失败模式中存在的断言。

7.6.1. 断言和实例基本类型

大多数断言仅限制特定基本类型内的值。当实例的类型不是关键字目标类型时,实例被认为符合断言。

例如,来自配套验证词汇表 [json-schema-validation] 的 "maxLength" 关键字:仅会限制某些字符串(太长)使其无效。如果实例是数字、布尔值、空值、数组或对象,那么它对该断言有效。

这种行为允许关键字更轻松地与可以是多种基本类型实例的实例一起使用。伴随验证词汇表还包含一个“type”关键字,它可以独立地将实例限制为一种或多种基本类型。这允许简洁地表达用例,例如可能返回特定长度的字符串或空值的函数:

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

如果“maxLength”还将实例类型限制为字符串,那么表达起来将非常繁琐,因为所写示例实际上不允许空值。除非明确指定,否则每个关键字都会单独评估,因此如果“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 将使用该描述,并将解释空值的本地定义描述附加到该描述。

请注意,其他应用程序可能会采取其他合理的方法。例如,应用程序可能会认为“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”关键字出现在元模式中时,它会声明哪些词汇表可用于引用该元模式的模式。词汇表定义关键字语义及其一般语法。
描述有效的模式语法
一个模式 MUST 成功地根据其元模式进行验证,元模式限制了可用关键字的语法。描述的语法应与声明的词汇表兼容;虽然可以描述不兼容的语法,但这样的元模式不太可能有用。

元模式独立于词汇表,以允许以不同的方式组合词汇表,并允许元模式作者强制执行额外的约束,例如禁止某些关键字或执行异常严格的语法验证,如在开发和测试周期中可能进行的那样。每个词汇表通常识别一个仅包含词汇表关键字的元模式。

元模式创作是 JSON Schema 的高级用法,因此元模式特性的设计强调灵活性而不是简单性。

8.1.1. "$schema" 关键字

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

该关键字的值 MUST 是一个 URI [RFC3986](包含方案),并且此 URI MUST 被规范化。当前模式 MUST 相对于由此 URI 标识的元模式有效。

如果此 URI 标识一个可检索的资源,则该资源 SHOULD 是 "application/schema+json" 媒体类型。

"$schema" 关键字 SHOULD 用于文档根模式对象中,并且 MAY 用于嵌入式模式资源的根模式对象中。它 MUST NOT 出现在非资源根模式对象中。如果在文档根模式中不存在,则结果行为由实现定义。

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

8.1.2. "$vocabulary" 关键字

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

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

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

对象属性的值 MUST 是布尔值。如果值为 true,则不识别词汇表的实现 MUST 拒绝处理使用 "$schema" 声明此元模式的任何模式。如果值为 false,则不识别词汇表的实现 SHOULD 继续处理此类模式。如果实现理解词汇表,则该值不会产生任何影响。

根据 6.5,未识别的关键字 SHOULD 被视为注释。对于由未识别词汇表定义的关键字,情况仍然如此。目前无法区分由词汇表定义的未识别关键字与不属于任何词汇表的关键字。

"$vocabulary" 关键字 SHOULD 用于任何旨在用作元模式的模式文档的根模式中。它 MUST NOT 出现在子模式中。¶a>

"$vocabulary" 关键字 MUST 在不作为元模式处理的模式文档中被忽略。这允许验证元模式 M 相对于其自身的元模式 M',而无需验证器理解由 M 声明的词汇表。

8.1.2.1. 默认词汇表

如果 "$vocabulary" 缺失,实现 MAY 根据元模式确定行为,如果从引用模式的 "$schema" 关键字的 URI 值中识别出元模式。这就是在词汇表存在之前如何识别行为(如 Hyper-Schema 使用)。

如果模式所引用的元模式未被识别或缺失,则行为由实现定义。如果实现继续处理模式,则它 MUST 假设使用核心词汇表。如果实现是为特定目的构建的,则它 SHOULD 假设使用与该目的最相关的词汇表。

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

8.1.2.2. 词汇表的不可继承性

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

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

更新的词汇表和元模式 URI MAY 在规范草案之间发布,以纠正错误。实现 SHOULD 考虑在此规范草案之后且在下一次草案之前日期的 URI,以指示与此处列出的 URI 相同的语法和语义。

8.2. 基本 URI、锚点和取消引用

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

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

8.2.1. "$id" 关键字

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

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

如果存在,则此关键字的值 MUST 是一个字符串,并且 MUST 代表一个有效的 URI 引用 [RFC3986]。此 URI 引用 SHOULD 被规范化,并且 MUST 解析为一个 绝对 URI [RFC3986](没有片段),或者解析为一个具有空片段的 URI。

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

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

绝对 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 Schema 文档的根模式 SHOULD 包含一个 "$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 节) 中定义具有相同名称的片段并使用 "$dynamicAnchor" 的最外层模式资源的 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" 属性的存在、不存在或内容采取任何其他操作。特别是,"$comment" 的值不应作为注释结果收集。

9. 加载和处理模式

9.1. 加载模式

9.1.1. 初始基准 URI

RFC3986 第 5.1 节 [RFC3986] 定义了如何确定文档的默认基准 URI。

信息性地,模式的初始基准 URI 是它被找到的 URI,无论是网络位置、本地文件系统还是任何其他可以通过任何已知方案的 URI 标识的情况。

如果模式文档在 "$id" 中没有定义任何显式基准 URI(嵌入在内容中),则基准 URI 是根据 RFC 3986 第 5 节 [RFC3986] 确定的。

如果没有已知的源,或者没有已知的源 URI 方案,则可以使用合适的实现特定默认 URI,如 RFC 3986 第 5.1.4 节 [RFC3986] 中所述。建议实现记录它们假设的任何默认基准 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 在将嵌入式模式移动到单独的文档并进行引用后将不再有效,因此应用程序和模式 SHOULD NOT 使用此类 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 有效,但使用嵌入式或引用资源的 "$id" 更健壮,除非专门希望在第二种(非嵌入式)安排中标识包含 "$ref" 的对象。

实现 MAY 选择不支持通过使用除资源的规范 URI 以外的基准以及相对于该基准的 JSON 指针片段的 URI 来寻址模式资源内容。因此,模式作者 SHOULD NOT 依赖此类 URI,因为使用它们可能会降低互操作性。 这样做是为了避免要求实现跟踪所有可能的基准 URI 和 JSON 指针片段的整个堆栈,因为如果模式资源被重新组织,所有基准 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 模式资源捆绑到同一个文档中,以方便传输。

每个嵌入式模式资源 MUST 被视为一个独立的模式资源,遵循标准模式加载和处理要求,包括确定词汇支持。

9.3.1. 捆绑

用于创建复合模式文档的捆绑过程被定义为获取对外部模式资源的引用(如 "$ref")并将引用的模式资源嵌入到引用文档中。捆绑 SHOULD 以这样一种方式完成,即基准文档和任何引用/嵌入文档中使用的所有 URI(用于引用)不需要更改。

每个嵌入式 JSON 模式资源 MUST 使用 "$id" 关键字标识自身,并且 SHOULD 使用 "$schema" 关键字标识它使用的方言,位于模式资源的根部。建议 "$id" 的 URI 标识符值为绝对 URI。

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

模式资源 MAY 嵌入到 "$defs" 以外的位置,其中位置被定义为模式值。

捆绑的模式资源 MUST NOT 通过替换引用它的模式对象或通过将模式资源包装在其他应用器关键字中来进行捆绑。

为了生成相同的输出,包含模式文档中对先前外部模式资源的引用 MUST NOT 被更改,现在解析为使用嵌入式模式资源的 "$id" 的模式。此类相同的输出包括验证评估以及生成的注释或错误中使用的 URI 或路径。

虽然捆绑过程通常是创建复合模式文档的主要方法,但手动创建也是可能的,并且预计有些人会手动创建,可能在以前没有单独的模式资源存在的情况下。

9.3.2. 不同的和默认方言

当单个文档中存在多个模式资源时,未定义应使用哪个方言处理的模式资源 MUST 使用与封闭资源相同的方言进行处理。

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

9.3.3. 验证

鉴于复合模式文档可能具有识别为使用不同方言的嵌入式资源,这些文档 SHOULD NOT 通过将元模式应用于复合模式文档作为实例来进行验证。建议提供替代验证过程来验证模式文档。每个模式资源 SHOULD 与其关联的元模式分别进行验证。 如果您知道要验证的是什么模式,您可以通过使用 "$id" 来识别该模式是否是复合模式文档,当不在文档的根部使用时,"$id" 会标识嵌入式资源。

所有嵌入式资源都识别为使用相同方言的复合模式文档,或者其中 "$schema" 被省略,因此默认为封闭资源的方言,MAY 通过应用适当的元模式来进行验证。

9.4. 注意事项

9.4.1. 防止无限递归

模式 MUST NOT 对实例运行到无限循环。例如,如果两个模式 "#alice" 和 "#bob" 都具有一个引用对方的 "allOf" 属性,则一个简单的验证器可能会陷入无限递归循环中,试图验证实例。模式 SHOULD NOT 使用这种无限递归嵌套;行为未定义。

9.4.2. 对可能的非模式的引用

子模式对象(或布尔值)通过与已知应用器关键字或与保留位置关键字(如 "$defs" (第 8.2.4 节))一起使用来识别,这些关键字将一个或多个子模式作为值。这些关键字可能是 "$defs" 和本文档中的标准应用器,也可能是来自已知词汇的扩展关键字,或实现特定的自定义关键字。

未知关键字的多级结构能够引入嵌套子模式,这将受到 "$id" 处理规则的约束。因此,无法可靠地实现此类未识别结构中的引用目标,并且由此产生的行为未定义。类似地,在已知关键字下,其值为已知不是模式的引用目标会导致未定义的行为,以避免给实现带来检测此类目标的负担。 这些场景类似于通过 HTTP 获取模式,但收到的响应的 Content-Type 不是 application/schema+json。实现当然可以尝试将其解释为模式,但源服务器没有保证它实际上是任何此类东西。因此,将其解释为模式存在安全隐患,并可能产生不可预测的结果。

请注意,与 "$defs" 具有相同语法和语义的单级自定义关键字不允许任何中间的 "$id" 关键字,因此在尝试使用任何引用目标作为模式的实现下,将表现正确。但是,这种行为是特定于实现的,MUST NOT 依赖于互操作性。

9.5. 关联实例和模式

9.5.1. 超媒体的用法

JSON 已经被 HTTP 服务器广泛采用,用于自动化的 API 和机器人。本节描述了如何使用支持媒体类型和 Web 链接 [RFC8288] 的协议,以更 RESTful 的方式增强 JSON 文档的处理。

9.5.1.1. 链接到模式

建议由模式描述的实例提供指向可下载 JSON 模式(使用链接关系“describedby”)的链接,如 链接数据协议 1.0,第 8.1 节 [W3C.REC-ldp-20150226] 中所定义。

在 HTTP 中,此类链接可以使用 Link 标头 [RFC8288] 附加到任何响应。以下是一个此类标头的示例:

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

9.5.1.2. 通过 HTTP 的用法

当用于网络上的超媒体系统时,HTTP [RFC7231] 通常是用于分发模式的首选协议。如果客户端的行为不当,并且比必要时更频繁地从网络中拉取模式(而可以将模式缓存很长时间),则会给服务器维护人员带来问题。

HTTP 服务器应该为 JSON 模式设置长期缓存标头。HTTP 客户端应该遵守缓存标头,并且不要在它们的有效期内重新请求文档。分布式系统应该使用共享缓存和/或缓存代理。

客户端应该设置或在 User-Agent 标头中添加特定于 JSON 模式实现或软件产品的标头。由于符号按重要性降序排列,因此 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 模式。

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

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

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

每个关键字都定义了一条规则,用于将子模式应用于子实例,特别是对象属性和数组项目,并将它们的结果组合起来。

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

10.3.1.1. prefixItems

"prefixItems" 的值必须是非空有效的 JSON 模式数组。

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

此关键字生成一个注释值,该值是此关键字应用子模式的最大索引。该值可以是布尔值 true,如果对实例的每个索引都应用了一个子模式,例如“items”关键字生成的注释。此注释影响“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 一样。

此词汇表的当前 URI(称为 Unevaluated 应用器词汇表)是:<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" 子模式必须应用于数组中的所有位置。如果来自任何相关注释的布尔值 true 存在,则 "unevaluatedItems" 必须被忽略。否则,子模式必须应用于任何大于 "prefixItems" 的最大注释值的索引,该索引不会出现在 "contains" 的任何注释值中。

这意味着在评估此关键字之前,必须评估 "prefixItems"、"items"、"contains" 以及所有就地应用器。扩展关键字的作者不得定义需要在此关键字之后评估的就地应用器。

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

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

11.3. unevaluatedProperties

"unevaluatedProperties" 的值必须是有效的 JSON Schema。

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

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

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

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

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

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

12. 输出格式

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

12.1. 格式

JSON Schema 输出使用第 4.2.1 节中描述的 JSON Schema 数据实例模型定义。实现 MAY 偏离此,只要它们各自的语言和平台支持,但 RECOMMENDED 将输出通过序列化或其他方式转换为此处定义的 JSON 格式。

12.2. 输出格式

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

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

实现 SHOULD 至少提供一种 "标志"、"基本" 或 "详细" 格式,并且 MAY 提供 "详细" 格式。如果它提供了一种或多种 "详细" 或 "详细" 格式,它也必须提供 "标志" 格式。实现 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": false
}

由于此格式不返回任何错误或注释,因此 RECOMMENDED 实现使用短路逻辑,以尽快返回失败或成功,只要可以确定结果。例如,如果 "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.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 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC3986]
Berners-Lee, T., Fielding, R.L. Masinter, "统一资源标识符 (URI):通用语法", STD 66, RFC 3986, DOI 10.17487/RFC3986, , <https://www.rfc-editor.org/info/rfc3986>.
[RFC6839]
Hansen, T.A. Melnikov, "附加媒体类型结构化语法后缀", RFC 6839, DOI 10.17487/RFC6839, , <https://www.rfc-editor.org/info/rfc6839>.
[RFC6901]
Bryan, P., Ed., Zyp, K.M. Nottingham, Ed., "JavaScript 对象表示法 (JSON) 指针", RFC 6901, DOI 10.17487/RFC6901, , <https://www.rfc-editor.org/info/rfc6901>.
[RFC8259]
Bray, T., Ed., "JavaScript 对象表示法 (JSON) 数据交换格式", STD 90, RFC 8259, DOI 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 6596, DOI 10.17487/RFC6596, , <https://www.rfc-editor.org/info/rfc6596>.
[RFC7049]
Bormann, C.P. Hoffman, "简洁二进制对象表示 (CBOR)", RFC 7049, DOI 10.17487/RFC7049, , <https://www.rfc-editor.org/info/rfc7049>.
[RFC7231]
Fielding, R., Ed.J. Reschke, Ed., "超文本传输协议 (HTTP/1.1):语义和内容", RFC 7231, DOI 10.17487/RFC7231, , <https://www.rfc-editor.org/info/rfc7231>.
[RFC8288]
Nottingham, M., "网页链接", RFC 8288, DOI 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 的 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": "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" 语义含义背后的逻辑。如果没有对语义的理解(在这个例子中,实例值必须等于或晚于 schema 中作为关键字值提供的日期),实现只能验证语法使用。在这种情况下,这意味着验证它是否为日期格式的字符串(使用 "pattern" 来确保即使 "format" 仅作为注释功能时也会进行验证,如验证规范 [json-schema-validation] 中所述)。

附录 E. 参考文献和生成用例

虽然引用存在预期对验证结果是透明的,但代码生成器和 UI 渲染器等生成用例通常认为引用在语义上是重要的。

为了使这种特定用例的语义明确,最佳实践是在同一个 schema 对象中创建用于注释关键字,与 $ref 等引用关键字并排使用。

例如,这里有一个假设的关键字,用于确定代码生成器是否应该将引用目标视为一个不同的类,以及这些类之间是如何相关的。请注意,这个例子仅仅是为了说明目的,并不打算提出一个功能性的代码生成关键字。

{
    "allOf": [
        {
            "classRelation": "is-a",
            "$ref": "classes/base.json"
        },
        {
            "$ref": "fields/common.json"
        }
    ],
    "properties": {
        "foo": {
            "classRelation": "has-a",
            "$ref": "classes/foo.json"
        },
        "date": {
            "$ref": "types/dateStruct.json",
        }
    }
}

这里,这个 schema 代表某种面向对象的类。 "allOf" 中的第一个引用被标记为基类。第二个引用没有分配类关系,这意味着代码生成器应该将目标的定义与这个定义结合起来,就像没有引用一样。

看一下属性, "foo" 被标记为对象组合,而 "date" 属性没有。它只是一个包含子字段的字段,而不是一个独立类的实例。

这种使用方式要求注释与引用在同一个对象中,并且必须能够识别为引用。

附录 F. 致谢

感谢 Gary Court、Francis Galiegue、Kris Zyp 和 Geraint Luff 对 JSON Schema 初稿的贡献。

感谢 Jason Desrosiers、Daniel Perrett、Erik Wilde、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" 的 schema 形式从验证规范移动到 "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
  • 详尽的 schema 标识示例
  • 用实现如何以及何时可能从另一个文档中知道一个 schema 来替换 "外部引用"
  • 用实现如何在解析过程中识别 schema 标识符来替换 "内部引用"
  • 解除引用以前的 "内部" 或 "外部" 引用始终是相同的过程
  • 轻微的格式改进
draft-handrews-json-schema-00
  • 使 schema 关键字词汇表的概念更加清晰
  • 注意 "integer" 的概念来自词汇表,而不是数据模型
  • 将关键字分类为断言或注释,并描述其一般行为
  • 根据广义断言解释布尔 schema
  • 为 schema 保留 "$comment" 以用于关于 schema 的不可见注释
  • 关于 "$id" 和片段的措辞改进
  • 注意使用递归引用扩展元模式的挑战
  • 添加 "application/schema-instance+json" 媒体类型
  • 推荐使用 "schema" 链接关系/参数而不是 "profile"
draft-wright-json-schema-01
  • 更新介绍
  • 允许任何 schema 为布尔值
  • "$schema" 不应该出现在子 schema 中,尽管这可能会改变
  • 将 "id" 更改为 "$id";所有核心关键字都以 "$" 为前缀
  • 澄清和正式化 application/schema+json 的片段
  • 注意对 CBOR 等可以在 JSON 数据模型中表示的格式的适用性
draft-wright-json-schema-00
  • 更新对 JSON 的引用
  • 更新对 HTTP 的引用
  • 更新对 JSON 指针的引用
  • "id" 的行为现在根据 RFC3986 指定
  • 将 URI 的词汇表用法与 RFC3986 对齐
  • 删除对 draft-pbryan-zyp-json-ref-03 的引用
  • 将 "$ref" 的使用限制在期望 schema 的任何地方
  • 添加 "JSON Schema 数据模型" 的定义
  • 添加额外的安全注意事项
  • 定义 "id" 的子 schema 标识符的使用
  • 重写关于与 HTTP 一起使用的部分
  • 重写关于 rel="describedBy" 和 rel="profile" 使用的部分
  • 修复了多个无效的示例
draft-zyp-json-schema-04
  • 从草案 v3 中抢救回来。
  • 将验证关键字拆分为单独的文档。
  • 将超媒体关键字拆分为单独的文档。
  • 拆分后的初始草案。
  • 强制使用 JSON 引用、JSON 指针。
  • 定义 "id" 的作用。定义 URI 解析范围。
  • 添加互操作性考虑因素。
draft-zyp-json-schema-00
  • 初始草案。

作者地址

Austin Wright (编辑)
Henry Andrews (编辑)
Ben Hutton (编辑)
邮递员
Greg Dennis