互联网工程任务组 A. Wright,编辑
互联网草案
预期状态:信息性 H. Andrews,编辑
过期时间:2020 年 3 月 20 日
B. Hutton,编辑
Wellcome Sanger Institute
G. Dennis
2019 年 9 月 17 日

JSON Schema:用于描述 JSON 文档的媒体类型
draft-handrews-json-schema-02

摘要

JSON Schema 定义了媒体类型“application/schema+json”,这是一种基于 JSON 的格式,用于描述 JSON 数据的结构。JSON Schema 断言 JSON 文档的外观,从 JSON 文档中提取信息的方式,以及如何与 JSON 文档进行交互。“application/schema-instance+json” 媒体类型提供了超出“application/json” 文档所能提供的功能,并与“application/schema+json” 进行更丰富的集成。

读者注意事项

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

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

要提供反馈,请使用此 issue 跟踪器,主页上列出的通信方法或电子邮件联系文档编辑。

此备忘录的状态

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

互联网草案是互联网工程任务组 (IETF) 的工作文档。请注意,其他组也可能将工作文档作为互联网草案发布。当前互联网草案列表位于 https://datatracker.ietf.org/drafts/current/。

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

此互联网草案将于 2020 年 3 月 20 日过期。

版权声明

版权所有 (c) 2019 IETF 信托和作为文档作者列出的个人。版权所有。

本文件受 BCP 78 和 IETF 信托关于 IETF 文档的法律条款 (https://trustee.ietf.org/license-info) 的约束,这些条款在发布本文件之日生效。请仔细阅读这些文档,因为它们描述了您对本文件的权利和限制。从本文件提取的代码组件必须包含简化的 BSD 许可证文本,如信托法律条款第 4.e 节所述,并且按简化的 BSD 许可证中所述提供,不提供任何担保。


目录

1. 引言

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

本规范定义了 JSON Schema 核心术语和机制,包括通过引用指向另一个 JSON Schema,反引用 JSON Schema 引用,指定正在使用的词汇表以及定义预期输出。

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

2. 约定和术语

本文档中的关键术语“必须”、“禁止”、“必需”、“应”、“不应”、“建议”、“不建议”、“推荐”、“可以”和“可选”应按 RFC 2119 中的说明进行解释。

本文档中的术语“JSON”、“JSON 文本”、“JSON 值”、“成员”、“元素”、“对象”、“数组”、“数字”、“字符串”、“布尔值”、“true”、“false”和“null”应按 RFC 8259 中的定义进行解释。

3. 概述

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

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

为了便于重复使用,关键字可以组织成词汇表。词汇表包含关键字列表及其语法和语义。

JSON Schema 可以通过定义其他词汇表来扩展,或者更非正式地通过定义任何词汇表之外的附加关键字来扩展。无法识别的单个关键字将被忽略,而对于无法识别的词汇表的行为,可以在声明正在使用的词汇表时进行控制。

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

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

用于结构验证或超媒体注释等目的的更多词汇表在其他文档中定义。

4. 定义

4.1. JSON 文档

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

在 JSON Schema 中,术语“JSON 文档”、“JSON 文本”和“JSON 值”是可互换的,因为它们定义了数据模型。

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

4.2. 实例

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

4.2.1. 实例数据模型

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

实例具有六种原始类型之一,以及取决于类型的可能值范围

null
JSON“null”生成
boolean
来自 JSON“true”或“false”生成的“true”或“false”值
object
来自 JSON“object”生成的将字符串映射到实例的无序属性集
array
来自 JSON“array”生成的实例的有序列表
number
来自 JSON“number”生成的任意精度十进制数
string
来自 JSON "string" 语法的 Unicode 码点字符串。

空白和格式问题,包括数据模型中相等的数字的不同词法表示,因此不在 JSON Schema 的范围内。希望处理这些词法表示差异的 JSON Schema 词汇表 应该定义关键字以精确地解释数据模型中格式化的字符串,而不是依赖于原始 JSON 表示 Unicode 字符的可用性。

由于一个对象不能有两个具有相同键的属性,因此对于试图在一个对象中定义两个具有相同键(“string” 语法)的属性(“member” 语法)的 JSON 文档的行为是未定义的。

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

4.2.2. 实例媒体类型

JSON Schema 旨在完全适用于 "application/json" 文档,以及使用 "+json" 结构化语法后缀的媒体类型。

每个媒体类型定义了一些对处理模式有用的功能,即媒体类型参数以及 URI 片段标识符语法和语义。这些特性分别在内容协商和计算实例中特定位置的 URI 时很有用。

本规范定义了 "application/schema-instance+json" 媒体类型,以便实例作者能够充分利用参数和片段标识符来实现这些目的。

4.2.3. 实例相等性

当且仅当两个 JSON 实例的类型相同,并且根据数据模型具有相同的值时,它们被称为相等。

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

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 的确定方式来控制模式标识。
断言
当应用于实例时会产生布尔结果。
注释
将信息附加到实例以供应用程序使用。
应用器
将一个或多个子模式应用于实例中的特定位置,并组合或修改其结果。
保留位置
不直接影响结果,但为特定目的保留一个位置,以确保互操作性。

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

扩展关键字,指的是本文档及其附录之外定义的那些关键字,可以自由定义其他行为。

JSON Schema 可以包含不是模式关键字的属性。未知关键字应该被忽略。

空模式是一个没有属性的 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 资源是 规范地绝对 URI 标识的模式。

根模式是包含正在讨论的整个 JSON 文档的模式。根模式始终是一个模式资源,其中 URI 是根据第 8.2.1 节中描述的方式确定的。

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

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

                        

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

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

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

5. 片段标识符

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

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

RFC 6901 中描述了将 JSON 指针用作 URI 片段标识符。对于 "application/schema+json",它支持两种片段标识符语法,包括空字符串在内的与 JSON 指针语法匹配的片段标识符必须解释为 JSON 指针片段标识符。

根据 W3C 的 片段标识符最佳实践,"application/schema+json" 中的普通名称片段标识符保留用于引用本地命名的模式。所有不匹配 JSON 指针语法的片段标识符必须解释为普通名称片段标识符。

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

6. 一般注意事项

6.1. JSON 值的范围

实例可以是 JSON 定义的任何有效 JSON 值。JSON Schema 不对类型施加任何限制:JSON Schema 可以描述任何 JSON 值,包括例如 null。

6.2. 编程语言独立性

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

6.3. 数学整数

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

为了保持一致性,整数 JSON 数字不应以小数部分进行编码。

6.4. 正则表达式

关键字可以使用正则表达式来表达约束,或者将实例值约束为正则表达式。这些正则表达式应该根据 ECMA 262,第 15.10.1 节 中描述的正则表达式方言有效。

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

最后,实现不得将正则表达式视为锚定,既不在开头也不在结尾。这意味着,例如,模式 "es" 匹配 "expression"。

6.5. 扩展 JSON Schema

任何实体都可以定义额外的模式关键字和模式词汇表。除了明确的协议之外,模式作者不应期望这些额外的关键字和词汇表得到不支持这些支持的实现的支持。实现应该忽略它们不支持的关键字。

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

7. 关键字行为

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

扩展关键字 SHOULD 停留在这些类别中,请记住,注释尤其灵活。复杂的行为通常最好根据注释数据委托给应用程序,而不是直接实现为模式关键字。但是,扩展关键字 MAY 为特殊目的定义其他行为。

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

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

7.1. 词法范围和动态范围

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

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

关键字 MAY 被定义为部分值,例如 URI 引用,该引用必须针对另一个值进行解析,例如另一个 URI 引用或完整的 URI,该值是通过 JSON 文档的词法结构找到的。"$id" 核心关键字和 "base" JSON 超模式关键字是这种行为的示例。此外,本规范中的 "$ref" 和 "$recursiveRef" 以这种方式解析其值,尽管它们不会改变如何解析进一步的值。

请注意,某些关键字,例如 "$schema",适用于整个模式文档的词法范围,因此 MUST 仅出现在模式资源的根模式中。

其他关键字可能会考虑到在评估模式期间存在的动态范围,通常与实例文档一起使用。最外面的动态范围是处理开始的模式文档的根模式。从该根模式到任何特定关键字的路径(包括可能已解析的任何 "$ref" 和 "$recursiveRef" 关键字)被认为是关键字的“验证路径”。 [CREF1]或者这应该是处理开始的模式对象,即使它不是根?这对 "$recursiveAnchor" 仅允许在根模式中但处理从子模式开始的情况有一些影响。

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

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

7.2. 关键字交互

关键字行为 MAY 被定义为 子模式 和/或相邻关键字的注释结果。此类关键字 MUST NOT 导致循环依赖。关键字 MAY 基于另一个关键字在同一个 模式对象 中存在或不存在来修改其行为。

7.3. 默认行为

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

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

由于注释收集在计算和内存方面都会增加显著的成本,因此实现 MAY 选择退出此功能。已知对实现有断言或应用程序行为依赖于注释结果的关键字 MUST 然后被视为错误,除非有可用的产生相同行为的替代实现。此类关键字 SHOULD 在适当的情况下描述合理的替代方法。本文件中的 "additionalItems" 和 "additionalProperties" 关键字说明了这种方法。

7.4. 标识符

标识符设置模式的规范 URI,或影响在 引用 中如何解析此类 URI,或两者兼而有之。本文件中定义的核心词汇表定义了几个识别关键字,最著名的是 "$id"。

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

虽然自定义标识符关键字是可能的,但词汇表设计者应注意不要破坏核心关键字的功能。例如,本规范中的 "$recursiveAnchor" 关键字将其 URI 解析效果限制在匹配的 "$recursiveRef" 关键字,保持 "$ref" 不受干扰。

7.5. 应用程序

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

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

应用程序关键字还定义了如何修改和/或组合子模式或引用模式布尔 断言 结果以产生应用程序的布尔结果。应用程序可以对子模式的断言结果应用任何布尔逻辑运算,但 MUST NOT 引入新的断言条件。

注释 结果根据每个注释关键字指定的规则进行组合。

7.5.1. 引用和引用模式

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

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

对于某些按引用应用程序,例如 "$ref",可以通过对模式文档的词法范围进行静态分析来确定引用模式。其他应用程序,例如 "$recursiveRef" 和 "$recursiveAnchor",可能使用动态范围,因此只能在使用实例评估模式的过程中才能解析。

7.6. 断言

JSON 模式可用于断言 JSON 文档的约束,该文档要么通过断言,要么失败断言。这种方法可以用于验证与约束的一致性,或者记录满足约束所需的内容。

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

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

7.6.1. 断言和实例原始类型

大多数断言只约束特定原始类型内的值。当实例的类型不是关键字目标的类型时,实例被认为符合断言。

例如,来自配套 验证词汇表 的 "maxLength" 关键字:只会限制某些(太长)字符串为有效。如果实例是数字、布尔值、空值、数组或对象,那么它相对于此断言是有效的。

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

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

                        

如果 "maxLength" 还将实例类型限制为字符串,那么表达起来将非常麻烦,因为按编写方式,示例实际上不允许空值。每个关键字都是单独评估的,除非明确指定了其他情况,因此,如果 "maxLength" 将实例限制为字符串,那么在 "type" 中包含 "null" 将不会有任何有用的效果。

7.7. 注释

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

注释附加到实例中的特定位置。由于许多子模式可以应用于任何单个位置,因此注释关键字需要指定对具有不同值的关键字的多个适用出现的任何非寻常处理。

与断言结果不同,注释数据可以采用各种形式,这些形式将提供给应用程序以供其自行使用。不希望 JSON 模式实现代表应用程序使用收集的信息。

除非另有说明,否则注释关键字的注释值是关键字的值。但是,其他行为也是可能的。例如,JSON 超模式 的 "links" 关键字是一种复杂的注释,它根据实例数据部分生成一个值。

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

7.7.1. 收集注释

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

收集的注释 MUST 包含以下信息

如果同一个关键字将来自多个模式位置的值附加到同一个实例位置,并且注释定义了组合此类值的流程,则组合后的值也必须与实例位置相关联。输出格式 本规范中描述的包含注释信息的内容满足此要求。

7.7.1.1. 区分多个值

应用程序可以根据贡献值的模式位置来决定使用多个注释值中的哪一个。这是为了允许灵活的使用。收集模式位置有助于这种使用。

例如,考虑以下模式,它使用来自验证规范的注释和断言。

请注意,一些行为了清晰起见而被换行。

{
    "title": "Feature list",
    "type": "array",
    "items": [
        {
            "title": "Feature A",
            "properties": {
                "enabled": {
                    "$ref": "#/$defs/enabledToggle",
                    "default": true
                }
            }
        },
        {
            "title": "Feature B",
            "properties": {
                "enabled": {
                    "description": "If set to null, Feature B
                                    inherits the enabled
                                    value from Feature A",
                    "$ref": "#/$defs/enabledToggle"
                }
            }
        }
    ],
    "$defs": {
        "enabledToggle": {
            "title": "Enabled",
            "description": "Whether the feature is enabled (true),
                            disabled (false), or under
                            automatic control (null)",
            "type": ["boolean", "null"],
            "default": null
        }
    }
}

                            

在这个例子中,功能 A 和功能 B 都使用可复用的“enabledToggle”模式。该模式使用“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. 注释和断言

生成错误断言结果的模式对象不得生成任何注释结果,无论是来自它们自己的关键字,还是来自子模式中的关键字。

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

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

                            

以及实例 "This is a string",标题注释“Integer Value”被丢弃,因为该模式对象中的类型断言失败。标题注释“String Value”被保留,因为实例通过了字符串类型断言。

7.7.1.3. 注释和应用器

除了可能定义他们自己的注释结果外,应用器关键字还会聚合在它们的子模式(s)或引用模式(s)中收集的注释。聚合注释值的规则由每个注释关键字定义,并且不受用于组合断言结果的逻辑的直接影响。

7.8. 保留位置

第四类关键字只是保留一个位置来保存可复用组件或模式作者感兴趣的数据,这些数据不适合复用。这些关键字不会影响验证或注释结果。它们在核心词汇表中的作用是确保位置可用于某些目的,并且不会被扩展关键字重新定义。

虽然这些关键字不会直接影响结果,但正如第8.2.4.4节中所解释的那样,保留可复用模式位置的未识别的扩展关键字在某些情况下可能会与引用产生不良的交互。

8. JSON 模式核心词汇表

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

为了引导进一步词汇表的处理,核心词汇表必须始终被认为是强制性的。使用"$vocabulary"关键字声明正在使用的词汇表的元模式必须显式地列出核心词汇表,该词汇表必须具有值为 true 的值,表示它是必需的。

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

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

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

相应元模式的当前 URI 为:<https://json-schema.fullstack.org.cn/draft/2019-09/meta/core>.

虽然“$”前缀没有正式保留给核心词汇表,但建议扩展关键字(在词汇表中或其他情况下)以“$”以外的字符开头,以避免将来可能发生的冲突。

8.1. 元模式和词汇表

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

元模式有两个目的

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

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

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

8.1.1. “$schema”关键字

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

此关键字的值必须是URI(包含一个方案),并且此 URI 必须被规范化。当前模式必须针对由此 URI 标识的元模式有效。

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

“$schema”关键字应该在资源根模式中使用。它不得出现在资源子模式中。如果从根模式中缺失,则结果行为是实现定义的。

如果单个文档中存在多个模式资源,则所有模式资源都应该具有相同的“$schema”值。同一个模式文档中“$schema”的不同值的结果是实现定义的。[CREF2]在同一个文档中使用多个“$schema”关键字将意味着特性集,因此行为可以在文档中改变。这将需要解决许多尚未明确定义的实现问题。因此,虽然在根模式中仅使用“$schema”的模式可能是模式编写的最佳实践,但实现行为可能会在未来的草案中进行修改或放宽。 [CREF3]为嵌入式模式资源做出的例外是为了允许将多个模式资源捆绑到一个模式文档中,而无需更改其内容,正如本规范后面所述。

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

8.1.2. “$vocabulary”关键字

“$vocabulary”关键字用于元模式中,以标识由该元模式描述的模式中可用的词汇表。它还用于指示每个词汇表是必需的还是可选的,从某种意义上说,实现必须理解必需的词汇表,才能成功处理模式。

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

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

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

根据6.5,未识别的关键字应该被忽略。对于由未识别词汇表定义的关键字,情况仍然如此。目前无法区分定义在词汇表中的未识别关键字与不在任何词汇表中的关键字。

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

对于那些没有被当作元模式处理的模式文档,"$vocabulary" 关键字**必须**被忽略。这样可以验证一个元模式 M 相对于它自己的元模式 M',而无需验证器理解 M 所声明的词汇表。

8.1.2.1. 默认词汇表

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

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

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

8.1.2.2. 词汇表的不可继承性

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

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

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

8.1.4. 检测元模式

如果正在检查一个模式是因为它被另一个模式的"$schema" 关键字识别为元模式,则实现**必须**识别该模式为元模式。这意味着单个模式文档有时可能被视为普通模式,而其他时候则被视为元模式。

在检查自身为元模式的模式的情况下,当实现开始将其作为普通模式处理时,它是在这些规则下进行处理的。但是,当由于检查其自身的"$schema" 值而第二次加载时,它被视为元模式。因此,在一次会话中,同一个文档以两种方式被处理。

实现**可以**允许将模式明确地作为元模式传递,用于实现特定的目的,例如预先加载常用的元模式并检查其词汇表支持要求。元模式作者**不应**期望这种功能在不同实现之间具有互操作性。

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

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

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

8.2.1. 初始基本 URI

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

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

如果模式文档使用"$id"(嵌入在内容中)定义了没有明确的基本 URI,则基本 URI 是根据RFC 3986 第 5 节确定的。

如果未知源或源的 URI 方案未知,则可以使用RFC 3986 第 5.1.4 节中所述的合适的实现特定的默认 URI。**建议**实现记录它们假设的任何默认基本 URI。

除非下一节中描述的"$id" 关键字出现在根模式中,否则该基本 URI **应该**被认为是模式文档根模式资源的规范 URI。

8.2.2. "$id" 关键字

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

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

如果存在,此关键字的值**必须**是一个字符串,并且**必须**表示一个有效的URI 引用。此 URI 引用**应该**被规范化,并且**必须**解析为一个绝对 URI(没有 fragment)。因此,"$id" **不应**包含非空的 fragment,并且**不应**包含空的 fragment。

由于 application/schema+json 媒体类型上下文中的空 fragment 指的是与没有 fragment 的基本 URI 相同的资源,因此实现**可以**通过删除 fragment 来规范化以空 fragment 结尾的 URI。但是,模式作者**不应**依赖于不同实现之间的这种行为。 [CREF6]这主要允许是因为旧的元模式在其 $id(或以前,id)中有一个空 fragment。将来的草案可能会完全禁止在"$id" 中使用空 fragment。

此 URI 同时充当模式资源中关键字内的相对 URI 引用的基本 URI,符合RFC 3986 第 5.1.1 节关于嵌入在内容中的基本 URI。

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

如果没有任何父模式对象明确地使用"$id" 将自己标识为资源,则基本 URI 是整个文档的 URI,如上一节中给出的步骤所确定的。

8.2.2.1. 识别根模式

JSON 模式文档的根模式**应该**包含一个"$id" 关键字,其值为一个绝对 URI(包含一个方案,但不包含 fragment)。

8.2.2.2. JSON 指针 fragment 和嵌入式模式资源

由于 JSON 指针 URI fragment 是根据模式文档的结构构造的,因此嵌入式模式资源及其子模式可以通过相对于其自身规范 URI 或相对于包含资源的 URI 的 JSON 指针 fragment 来标识。

从概念上讲,一组链接的模式资源应该表现出相同行为,无论每个资源是通过模式引用连接的独立文档,还是结构化为单个文档,其中一个或多个模式资源作为子模式嵌入。

由于当嵌入式模式被移到独立的文档并被引用时,涉及相对于父模式资源的 URI 的 JSON 指针 fragment 的 URI 将不再有效,因此应用程序和模式**不应**使用此类 URI 来标识嵌入式模式资源或其内部位置。

考虑以下包含另一个嵌入式模式资源的模式文档

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

                            

URI "https://example.com/foo#/items/additionalProperties" 指向嵌入式资源中 "additionalProperties" 关键字的模式。但是,该模式的规范 URI 为 "https://example.com/bar#/additionalProperties"。

现在考虑以下两个使用 URI 值对"$ref"进行引用的链接模式资源

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

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

                            

在这里,我们看到该 "additionalProperties" 子模式的规范 URI 仍然有效,而以"#/items/$ref" 开头的 fragment 的非规范 URI 现在解析为空。

还请注意,"https://example.com/foo#/items" 在两种安排中都有效,但解析为不同的值。此 URI 最终的功能类似于资源的检索 URI。虽然有效,但检查解析的值,并使用"$id"(如果值是子模式),或解析引用并使用引用目标的"$id",是更好的做法。

实现**可以**选择不支持通过非规范 URI 对模式进行寻址。因此,**建议**模式作者只使用规范 URI,因为使用非规范 URI 可能会降低模式的互操作性。 [CREF7]这样做是为了避免要求实现跟踪一堆可能的基 URI 和每个 URI 的 JSON 指针 fragment,因为如果模式资源被重新组织,除一个之外的所有 URI 都会变得很脆弱。有些人认为这很容易,所以没有必要禁止它,而另一些人则认为这会使模式识别变得复杂,应该禁止它。鼓励对这个问题进行反馈。

此类非规范 URI 的更多示例,以及应该使用的适当规范 URI,在附录A 中提供。

8.2.3. 使用"$anchor" 定义位置无关的标识符

使用 JSON 指针 fragment 需要了解模式的结构。在编写旨在提供可重用模式的模式文档时,可能更倾向于使用不受任何特定结构位置约束的纯名称 fragment。这样,子模式就可以被重新定位,而无需更新 JSON 指针引用。

"$anchor" 关键字用于指定此类 fragment。它是一个标识符关键字,只能用于创建纯名称 fragment。

如果存在,此关键字的值**必须**是一个字符串,它**必须**以一个字母([A-Za-z])开头,后面可以跟任意数量的字母、数字([0-9])、连字符("-")、下划线("_")、冒号(":")或点(".")。 [CREF8]请注意,锚点字符串不包括"#" 字符,因为它不是 URI 引用。"$anchor": "foo" 在 URI 中使用时会变为 fragment "#foo"。有关完整示例,请参见下文。

将生成的 fragment 附加到的基本 URI 由"$id" 关键字确定,如上一节所述。如果两个"$anchor" 关键字位于同一个模式文档中,但应用于不同的基本 URI,则**可以**具有相同的值,因为生成的完整 URI 将是不同的。但是,如果两个"$anchor" 关键字具有相同的值和相同的基本 URI,则其效果是未定义的。如果检测到这种使用方式,实现**可以**引发错误。

8.2.4. 模式引用

一些关键字可以用于引用一个要应用于当前实例位置的模式。"$ref" 和 "$recursiveRef" 是应用关键字,将引用的模式应用于实例。"$recursiveAnchor" 是一个标识符关键字,它控制如何确定解析"$recursiveRef" 的 URI 引用值的基 URI。

由于"$ref" 和 "$recursiveRef" 的值是 URI 引用,因此这允许将模式跨多个文件外部化或划分,并提供通过自引用验证递归结构的能力。

这些关键字生成的解析后的 URI 不一定是一个网络定位器,而只是一个标识符。如果它是一个可网络寻址的 URL,则该模式不必从该地址下载,并且实现 SHOULD NOT 假设他们在遇到可网络寻址的 URI 时应该执行网络操作。

8.2.4.1. 使用“$ref”的直接引用

“$ref”关键字是一个应用器,用于引用静态标识的模式。其结果是所引用模式的结果。[CREF9]请注意,这种关于结果如何确定的定义意味着其他关键字可以与“$ref”一起出现在同一个模式对象中。

“$ref”属性的值 MUST 是一个字符串,该字符串是一个 URI 引用。相对于当前 URI 基准解析后,它将生成要应用的模式的 URI。

8.2.4.2. 使用“$recursiveRef”和“$recursiveAnchor”的递归引用

“$recursiveRef”和“$recursiveAnchor”关键字用于构建可扩展的递归模式。递归模式是指具有对其自身根的引用的模式,该根由空片段 URI 引用 (“#”) 标识。

简而言之,“$recursiveRef”的行为与“$ref”相同,除了当其目标模式包含值为 true 的“$recursiveAnchor”时。在这种情况下,将检查动态范围以确定新的基本 URI,并且“$recursiveRef”中的 URI 引用将针对该基本 URI 重新评估。与使用“$id”的基本 URI 更改不同,使用“$recursiveAnchor”的更改是在每次解析“$recursiveRef”时计算的,并且不会影响任何其他关键字。

有关使用这些关键字的示例,请参见附录 C[CREF10]先前草案中的超模式元模式与本草案之间的区别极大地证明了这些关键字的效用。

8.2.4.2.1. 使用“$recursiveRef”的动态递归引用

“$recursiveRef”属性的值 MUST 是一个字符串,该字符串是一个 URI 引用。它是一个按引用应用器,使用动态计算的基本 URI 来解析其值。

此关键字的行为仅针对值“#”定义。实现 MAY 选择将其他值视为错误。[CREF11]此限制将来可能会放宽,但到目前为止,只有值“#”具有明确的用例。

“$recursiveRef”的值最初相对于当前基本 URI 解析,方式与“$ref”相同。

检查由生成的 URI 标识的模式中是否存在“$recursiveAnchor”,并根据下一节中针对该关键字的描述计算新的基本 URI。

最后,“$recursiveRef”的值相对于根据“$recursiveAnchor”确定的新基本 URI 解析,生成最终解析的引用 URI。

请注意,在没有“$recursiveAnchor”的情况下(以及在某些情况下存在“$recursiveAnchor”的情况下),“$recursiveRef”的行为与“$ref”相同。

与“$ref”一样,此关键字的结果是所引用模式的结果。

8.2.4.2.2. 使用“$recursiveAnchor”启用递归

“$recursiveAnchor”属性的值 MUST 是一个布尔值。

“$recursiveAnchor”用于在运行时动态标识“$recursiveRef”的基本 URI,方法是标记此类计算可以开始的位置以及停止的位置。此关键字 MUST NOT 影响其他关键字的基本 URI,除非它们明确定义为依赖于它。

如果设置为 true,则当包含模式对象用作“$recursiveRef”的目标时,将通过检查动态范围来确定新的基本 URI,以查找也包含值为 true 的“$recursiveAnchor”的最外层模式。然后使用该模式的基本 URI 作为动态基本 URI。

如果没有这样的模式,则基本 URI 保持不变。

如果此关键字设置为 false,则基本 URI 保持不变。

省略此关键字的行为与值为 false 相同。

8.2.4.3. 防止无限递归

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

8.2.4.4. 对可能非模式的引用

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

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

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

8.2.4.5. 加载引用的模式

使用 URI 来标识远程模式并不一定意味着下载任何东西,而是 JSON 模式实现 SHOULD 事先了解它们将使用哪些模式以及标识它们的 URI。

当下载模式时,例如由不知道在运行时要下载哪些模式的通用用户代理下载时,请参见超媒体的使用

实现 SHOULD 能够将任意 URI 与任意模式关联起来,或者根据验证器对模式的信任程度,自动将模式的“$id”给定的 URI 关联起来。此类 URI 和模式可以在处理实例之前提供给实现,或者可以在处理模式文档时在模式文档中进行标记,从而生成如附录A中所示的关联。

模式 MAY(并且可能将)具有多个 URI,但 URI 无法标识多个模式。当多个模式尝试标识为同一个 URI 时,验证器 SHOULD 产生错误条件。

8.2.4.6. 取消引用

模式可以使用已分配给它们的任何 URI 来标识,包括 JSON 指针或由“$id”直接给出的 URI。在所有情况下,取消引用“$ref”引用都涉及首先根据RFC 3986将它的值作为 URI 引用相对于当前基本 URI 解析。

如果生成的 URI 标识当前文档中的模式,或已提供给实现的另一个模式文档中的模式,则 SHOULD 自动使用该模式。

例如,考虑以下模式

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

                            

当实现遇到<#/$defs/single>模式时,它将“$id”URI 引用相对于当前基本 URI 解析以形成<https://example.net/root.json#item>。

当实现随后查看<#/items>模式时,它会遇到<#item>引用,并将此解析为<https://example.net/root.json#item>,它已在此同一文档中定义,因此可以自动使用。

当实现遇到对“other.json”的引用时,它会将此解析为<https://example.net/other.json>,该模式未在此文档中定义。如果已向实现提供了具有该标识符的模式,则也可以自动使用它。[CREF13]当引用模式未知时,实现应该怎么做?在哪些情况下允许自动网络取消引用?同源策略?用户可配置选项?在由超模式描述的不断发展的 API 的情况下,预计会动态向系统添加新模式,因此,不可能绝对要求预加载模式文档。

8.2.5. 使用“$defs”重用模式

“$defs”关键字保留一个位置,供模式作者将可重用 JSON 模式内联到更通用的模式中。该关键字不会直接影响验证结果。

此关键字的值 MUST 是一个对象。此对象的每个成员值 MUST 是一个有效的 JSON 模式。

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

                            

例如,以下是一个描述正整数数组的模式,其中正整数约束是“$defs”中的子模式

8.3. 使用“$comment”进行注释

此关键字保留一个位置,供模式作者向模式的读者或维护者提供注释。

此关键字的值 MUST 是一个字符串。实现 MUST NOT 将此字符串显示给最终用户。用于编辑模式的工具 SHOULD 支持显示和编辑此关键字。此关键字的值 MAY 用于调试或错误输出,这些输出旨在用于使用模式的开发人员。

模式词汇表 SHOULD 允许在包含词汇表关键字的任何对象中使用“$comment”。除非词汇表明确禁止,否则实现 MAY 假设允许“$comment”。词汇表 MUST NOT 指定“$comment”除了本规范中描述的效果之外的任何效果。

将其他媒体类型或编程语言翻译成 application/schema+json 或从 application/schema+json 翻译成其他媒体类型或编程语言的工具 MAY 选择将该媒体类型或编程语言的原生注释转换为“$comment”值或从“$comment”值转换。当原生注释和“$comment”属性都存在时,此类翻译的行为是实现依赖的。

实现 SHOULD 将“$comment”与未知扩展关键字相同对待。它们 MAY 在处理过程中的任何时候都删除“$comment”值。特别是,这允许在部署的模式的大小成为问题时缩短模式。

实现 MUST NOT 根据“$comment”属性的存在、不存在或内容采取任何其他操作。特别是,MUST NOT 将“$comment”的值作为注释结果收集。

9. 应用子模式的词汇表

本节定义了一个应用器关键字词汇表,该词汇表 RECOMMENDED 用于作为其他词汇表的基础。

不使用“$vocabulary”的元模式 SHOULD 被认为需要此词汇表,就像它的 URI 存在并且值为 true 一样。

此词汇表(称为应用器词汇表)的当前 URI 是:<https://json-schema.fullstack.org.cn/draft/2019-09/vocab/applicator>

相应的元模式的当前 URI 是:<https://json-schema.fullstack.org.cn/draft/2019-09/meta/applicator>

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

9.1. 关键字独立性

模式关键字通常独立运行,不会影响彼此的结果。

为了模式作者的方便,此词汇表中的关键字之间存在一些例外。

9.2. 用于在原位应用子模式的关键字

这些关键字将子模式应用于实例中的同一位置,父模式正在应用于该位置。它们允许以各种方式组合或修改子模式结果。

9.2.1. 用于使用布尔逻辑应用子模式的关键字

这些关键字对应于用于组合或修改子模式的布尔断言结果的逻辑运算符。它们对注释收集没有直接影响,尽管它们允许将相同的注释关键字应用于具有不同值的实例位置。注释关键字定义了组合这些值的自身规则。

9.2.1.1. allOf

此关键字的值 MUST 为非空数组。数组的每个项目 MUST 为有效的 JSON 模式。

如果实例成功验证了此关键字的值定义的所有模式,则它将成功验证此关键字。

9.2.1.2. anyOf

此关键字的值 MUST 为非空数组。数组的每个项目 MUST 为有效的 JSON 模式。

如果实例成功验证了此关键字的值定义的至少一个模式,则它将成功验证此关键字。请注意,当收集注释时, MUST 检查所有子模式,以便从每个成功验证的子模式中收集注释。

9.2.1.3. oneOf

此关键字的值 MUST 为非空数组。数组的每个项目 MUST 为有效的 JSON 模式。

如果实例成功验证了此关键字的值定义的正好一个模式,则它将成功验证此关键字。

9.2.1.4. not

此关键字的值 MUST 为有效的 JSON 模式。

如果实例未能成功验证此关键字定义的模式,则它将针对此关键字有效。

9.2.2. 用于有条件地应用子模式的关键字

其中三个关键字协同工作,根据另一个子模式的结果实现子模式的有条件应用。第四个是特定条件情况的快捷方式。

"if","then" 和 "else" MUST NOT 在子模式边界之间相互影响。换句话说,"allOf" 的一个分支中的 "if" MUST NOT 对另一个分支中的 "then" 或 "else" 产生影响。

当 "if","then" 或 "else" 不存在时,没有默认行为。特别是, MUST NOT 将它们视为存在于空模式中,并且当 "if" 不存在时, both "then" and "else" MUST 被完全忽略。

9.2.2.1. if

此关键字的值 MUST 为有效的 JSON 模式。

此关键字子模式的验证结果对整体验证结果没有直接影响。相反,它控制评估 "then" 或 "else" 关键字中的哪一个。

成功验证此关键字子模式的实例 MUST 也针对 "then" 关键字的子模式值有效,如果存在。

未能验证此关键字子模式的实例 MUST 也针对 "else" 关键字的子模式值有效,如果存在。

如果 注释 正在被收集,它们将按照通常的方式从此关键字的子模式中收集,包括当关键字存在而没有 "then" 或 "else" 时。

9.2.2.2. then

此关键字的值 MUST 为有效的 JSON 模式。

当 "if" 存在并且实例成功验证了其子模式时,如果实例还成功验证了此关键字的子模式,则验证成功针对此关键字。

当 "if" 不存在或实例未能验证其子模式时,此关键字无效。在这种情况下,实现 MUST NOT 针对此关键字评估实例,无论是用于验证还是用于注释收集目的。

9.2.2.3. else

此关键字的值 MUST 为有效的 JSON 模式。

当 "if" 存在并且实例未能验证其子模式时,如果实例成功验证了此关键字的子模式,则验证成功针对此关键字。

当 "if" 不存在或实例成功验证了其子模式时,此关键字无效。在这种情况下,实现 MUST NOT 针对此关键字评估实例,无论是用于验证还是用于注释收集目的。

9.2.2.4. dependentSchemas

此关键字指定了如果实例是对象并包含特定属性,则进行评估的子模式。

此关键字的值 MUST 为对象。对象中的每个值 MUST 为有效的 JSON 模式。

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

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

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

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

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

9.3.1.1. items

"items" 的值 MUST 既是有效的 JSON 模式,又是有效的 JSON 模式数组。

如果 "items" 是一个模式,则如果数组中的所有元素都成功验证了该模式,则验证成功。

如果 "items" 是一个模式数组,则如果实例的每个元素都针对同一位置的模式(如果有)成功验证,则验证成功。

此关键字生成一个注释值,该值是此关键字应用子模式的最大索引。如果子模式被应用于实例的每个索引,则该值 MAY 为布尔值 true,例如当 "items" 是一个模式时。

将多个模式的 "items" 关键字应用于相同实例位置的注释结果通过将组合结果设置为 true(如果任何值都为 true),否则保留最大的数字值来组合。

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

9.3.1.2. additionalItems

"additionalItems" 的值 MUST 为有效的 JSON 模式。

此关键字的行为取决于 "items" 在同一模式对象中存在与否及其注释结果。如果 "items" 存在并且其注释结果为数字,则如果大于该数字的每个实例元素都针对 "additionalItems" 成功验证,则验证成功。

否则,如果 "items" 不存在或其注释结果为布尔值 true,则 MUST 忽略 "additionalItems"。

如果 "additionalItems" 子模式被应用于实例数组中的任何位置,则它会生成一个布尔值 true 的注释结果,类似于 "items" 的单一模式行为。如果来自应用于相同实例位置的任何子模式的任何 "additionalItems" 关键字生成一个 true 的注释值,则来自这些关键字的组合结果也是 true。

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

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

9.3.1.3. unevaluatedItems

"unevaluatedItems" 的值 MUST 为有效的 JSON 模式。

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

如果存在 "items" 注释并且其注释结果为数字,并且不存在 "additionalItems" 或 "unevaluatedItems" 注释,则如果大于 "items" 注释的每个实例元素都针对 "unevaluatedItems" 成功验证,则验证成功。

否则,如果任何 "items","additionalItems" 或 "unevaluatedItems" 注释存在并且值为布尔值 true,则 MUST 忽略 "unevaluatedItems"。但是,如果这些注释都不存在,则 MUST 将 "unevaluatedItems" 应用于数组中的所有位置。

这意味着 MUST 在评估此关键字之前评估 "items","additionalItems" 和所有原位应用器。扩展关键字的作者 MUST NOT 定义需要在评估此关键字之前评估的原位应用器。

如果 "unevaluatedItems" 子模式被应用于实例数组中的任何位置,则它会生成一个布尔值 true 的注释结果,类似于 "items" 的单一模式行为。如果来自应用于相同实例位置的任何子模式的任何 "unevaluatedItems" 关键字生成一个 true 的注释值,则来自这些关键字的组合结果也是 true。

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

不支持收集注释的实现 MUST 在遇到此关键字时引发错误。

9.3.1.4. contains

此关键字的值 MUST 为有效的 JSON 模式。

如果数组实例中至少有一个元素针对给定模式有效,则该实例针对 "contains" 有效。请注意,当收集注释时, MUST 将子模式应用于每个数组元素,即使在找到第一个匹配项之后也是如此。这是为了确保收集所有可能的注释。

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

9.3.2.1. properties

"properties" 的值 MUST 为对象。此对象的每个值 MUST 为有效的 JSON 模式。

如果对实例和此关键字的值中出现的每个名称,该名称的子实例都成功验证了相应的模式,则验证成功。

此关键字的注释结果是此关键字匹配的实例属性名称集。将多个模式的 "properties" 关键字应用于相同实例位置的注释结果通过取集合的并集来组合。

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

9.3.2.2. patternProperties

"patternProperties" 的值 MUST 为对象。此对象的每个属性名称 SHOULD 为有效的正则表达式,符合 ECMA 262 正则表达式方言。此对象的每个属性值 MUST 为有效的 JSON 模式。

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

此关键字的注释结果是与该关键字匹配的实例属性名称的集合。来自多个模式的 "patternProperties" 关键字对同一实例位置应用的注释结果通过取集合的并集来组合。

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

9.3.2.3. additionalProperties

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

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

对于所有此类属性,如果子实例通过 "additionalProperties" 模式验证,则验证成功。

此关键字的注释结果是此关键字子模式验证的实例属性名称的集合。来自多个模式的 "additionalProperties" 关键字对同一实例位置应用的注释结果通过取集合的并集来组合。

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

实现可以自由选择以其他方式实现或优化此关键字,以产生相同的效果,例如通过直接检查 "properties" 中的名称和 "patternProperties" 中的模式与实例属性集。不支持注释收集的实现必须这样做。

9.3.2.4. unevaluatedProperties

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

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

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

对于所有此类属性,如果子实例通过 "unevaluatedProperties" 模式验证,则验证成功。

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

此关键字的注释结果是此关键字子模式验证的实例属性名称的集合。来自多个模式的 "unevaluatedProperties" 关键字对同一实例位置应用的注释结果通过取集合的并集来组合。

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

不支持收集注释的实现 MUST 在遇到此关键字时引发错误。

9.3.2.5. propertyNames

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

如果实例是对象,则此关键字验证实例中的每个属性名称是否通过提供的模式验证。注意,模式测试的属性名称将始终是字符串。

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

10. 输出格式

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

10.1. 格式

JSON Schema 输出使用第 4.2.1 节中描述的 JSON Schema 数据实例模型定义。实现可以根据其特定语言和平台进行偏差,但是建议输出通过序列化或其他方式可转换为本文档中定义的 JSON 格式。

10.2. 输出格式

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

实现应该至少提供 "标志"、"基本" 或 "详细" 格式,并且可以提供 "详细" 格式。如果它提供了一个或多个复杂格式,它也必须提供 "标志" 格式。实现应该在文档中指定它们支持哪些格式。

10.3. 最小信息

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

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

实现可以自由选择提供其他信息。

10.3.1. 关键字相对位置

遵循验证路径的验证关键字的相对位置。该值必须用 JSON 指针表示,并且必须包含任何按引用应用器,例如 "$ref" 或 "$recursiveRef"。

#/properties/width/$ref/minimum

                        

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

此信息的 JSON 键为 "keywordLocation"。

10.3.2. 关键字绝对位置

验证关键字的绝对、解除引用的位置。该值必须用绝对 URI 表示,使用相关模式对象的规范 URI,并且绝对不能包含按引用应用器,例如 "$ref" 或 "$recursiveRef" 作为非终端路径组件。如果错误或注释是针对该关键字的,例如不可解析的引用,它可以以这些关键字结尾。

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

                        

仅当相对位置不包含任何引用或模式未声明绝对 URI 作为其 "$id" 时,才能省略此信息。

此信息的 JSON 键为 "absoluteKeywordLocation"。

10.3.3. 实例位置

正在验证的实例中 JSON 值的位置。该值必须用 URI 片段编码的 JSON 指针表示。

此信息的 JSON 键为 "instanceLocation"。

10.3.4. 错误或注释

验证产生的错误或注释。

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

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

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

10.3.5. 嵌套结果

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

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

10.4. 输出结构

输出必须是一个对象,包含一个名为 "valid" 的布尔属性。当需要有关结果的附加信息时,输出还必须包含 "errors" 或 "annotations",如下所述。

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

{
  "$id": "https://example.com/polygon",
  "$schema": "https://json-schema.fullstack.org.cn/draft/2019-09/schema",
  "$defs": {
    "point": {
      "type": "object",
      "properties": {
        "x": { "type": "number" },
        "y": { "type": "number" }
      },
      "additionalProperties": false,
      "required": [ "x", "y" ]
    }
  },
  "type": "array",
  "items": { "$ref": "#/$defs/point" },
  "minItems": 3
}

[
  {
    "x": 2.5,
    "y": 1.3,
  },
  {
    "x": 1,
    "z": 6.7
  }
]

                    

此实例将无法验证并产生错误,但推断产生注释的通过模式的示例很简单。

具体来说,它将产生的错误是

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

10.4.1. 标志

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

{
  "valid": false
}

                        

由于此格式不返回任何错误或注释,因此建议实现使用短路逻辑,以便在确定结果后立即返回失败或成功。例如,如果 "anyOf" 关键字包含五个子模式,而第二个子模式通过,则无需检查另外三个。逻辑可以简单地返回成功。

10.4.2. 基本

"基本" 结构是输出单元的扁平列表。

{
  "valid": false,
  "errors": [
    {
      "keywordLocation": "#",
      "instanceLocation": "#",
      "error": "A subschema had errors."
    },
    {
      "keywordLocation": "#/items/$ref",
      "absoluteKeywordLocation":
        "https://example.com/polygon#/$defs/point",
      "instanceLocation": "#/1",
      "error": "A subschema had errors."
    },
    {
      "keywordLocation": "#/items/$ref/required",
      "absoluteKeywordLocation":
        "https://example.com/polygon#/$defs/point/required",
      "instanceLocation": "#/1",
      "error": "Required property 'y' not found."
    },
    {
      "keywordLocation": "#/items/$ref/additionalProperties",
      "absoluteKeywordLocation":
        "https://example.com/polygon#/$defs/point/additionalProperties",
      "instanceLocation": "#/1/z",
      "error": "Additional property 'z' found but was invalid."
    },
    {
      "keywordLocation": "#/minItems",
      "instanceLocation": "#",
      "error": "Expected at least 3 items but found 2"
    }
  ]
}

                        

10.4.3. 详细

"详细" 结构基于模式,对于人和机器来说可能更易读。以这种方式组织结构使错误之间的关联更加明显。例如,缺少 "y" 属性和多余的 "z" 属性都源于实例中的同一位置,这在 "基本" 结构中并不立即明显。在层次结构中,更容易识别相关性。

以下规则控制结果对象的构建

分支节点不需要错误消息或注释。

{
  "valid": false,
  "keywordLocation": "#",
  "instanceLocation": "#",
  "errors": [
    {
      "valid": false,
      "keywordLocation": "#/items/$ref",
      "absoluteKeywordLocation":
        "https://example.com/polygon#/$defs/point",
      "instanceLocation": "#/1",
      "errors": [
        {
          "valid": false,
          "keywordLocation": "#/items/$ref/required",
          "absoluteKeywordLocation":
            "https://example.com/polygon#/$defs/point/required",
          "instanceLocation": "#/1",
          "error": "Required property 'y' not found."
        },
        {
          "valid": false,
          "keywordLocation": "#/items/$ref/additionalProperties",
          "absoluteKeywordLocation":
            "https://example.com/polygon#/$defs/point/additionalProperties",
          "instanceLocation": "#/1/z",
          "error": "Additional property 'z' found but was invalid."
        }
      ]
    },
    {
      "valid": false,
      "keywordLocation": "#/minItems",
      "instanceLocation": "#",
      "error": "Expected at least 3 items but found 2"
    }
  ]
}

                        

10.4.4. 详细

"详细" 结构是一个完全实现的层次结构,与模式完全匹配。此结构在形式生成和验证中具有应用,其中错误的位置很重要。

此结构与 "详细" 结构的主要区别在于返回所有结果。这包括否则将被删除的子模式验证结果(例如,失败验证的注释、`not` 关键字中的成功验证等)。因此,建议每个节点也包含一个 `valid` 属性以指示该节点的验证结果。

由于此输出结构可能非常大,因此出于简洁起见,这里给出了一个较小的示例。上面示例的完整输出结构的 URI 是:<https://json-schema.fullstack.org.cn/draft/2019-09/output/verbose-example>.

// schema
{
  "$id": "https://example.com/polygon",
  "$schema": "https://json-schema.fullstack.org.cn/draft/2019-09/schema",
  "type": "object",
  "properties": {
    "validProp": true,
  },
  "additionalProperties": false
}

// instance
{
  "validProp": 5,
  "disallowedProp": "value"
}

// result
{
  "valid": false,
  "keywordLocation": "#",
  "instanceLocation": "#",
  "errors": [
    {
      "valid": true,
      "keywordLocation": "#/type",
      "instanceLocation": "#"
    },
    {
      "valid": true,
      "keywordLocation": "#/properties",
      "instanceLocation": "#"
    },
    {
      "valid": false,
      "keywordLocation": "#/additionalProperties",
      "instanceLocation": "#",
      "errors": [
        {
          "valid": false,
          "keywordLocation": "#/additionalProperties",
          "instanceLocation": "#/disallowedProp",
          "error": "Additional property 'disallowedProp' found but was invalid."
        }
      ]
    }
  ]
}

                        

10.4.5. 输出验证模式

为了方便起见,JSON Schema 已被提供用于验证实现生成的输出。其 URI 是:<https://json-schema.fullstack.org.cn/draft/2019-09/output/schema>.

11. 超媒体的使用

JSON 已被广泛采用,用于 HTTP 服务器的自动化 API 和机器人。本节介绍如何在与支持媒体类型和 Web 链接 的协议一起使用时,以更 RESTful 的方式增强对 JSON 文档的处理。

11.1. 链接到模式

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

在 HTTP 中,可以使用 Link 标头 将此类链接附加到任何响应。此类标头的示例如下:

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

                    

11.2. 通过媒体类型参数标识模式

媒体类型可能允许使用“schema”媒体类型参数,这使 HTTP 服务器能够基于模式执行内容类型协商。媒体类型参数必须是空格分隔的 URI 列表(即相对引用无效)。

使用媒体类型 application/schema-instance+json 时,必须提供“schema”参数。

使用媒体类型 application/schema+json 时,可以提供“schema”参数。如果提供,它应该包含与“$schema”关键字标识的相同 URI,并且可以包含其他 URI。“$schema”URI 必须被视为模式的规范元模式,无论是否存在作为媒体类型参数的备用或附加元模式。

模式 URI 是不透明的,不应该自动取消引用。如果实现不理解所提供模式的语义,则实现可以改为遵循“describedby”链接(如果有),这些链接可能提供有关如何处理模式的信息。由于“schema”不一定指向网络位置,因此“describedby”关系用于链接到可下载模式。但是,为了简化起见,模式作者应尽可能使这些 URI 指向同一资源。

在 HTTP 中,媒体类型参数将发送到 Content-Type 标头中

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

                    

多个模式用空格分隔,表示实例符合所有列出的模式

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

                    

媒体类型参数也用于 HTTP 的 Accept 请求标头

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

                    

与 Content-Type 一样,同一字符串中的多个模式参数请求符合所有列出模式的实例。

与 Content-Type 不同,Accept 可以包含多个值以指示客户端可以接受几种媒体类型。在上面的示例中,请注意,两种媒体类型仅在其模式参数值上有所不同。这请求符合至少一个已识别模式的 application/json 表示形式。

[CREF14]本段假设我们可以注册“schema”链接关系。我们现在应该指定类似“tag:json-schema.org,2017:schema”的内容吗? HTTP 也可以在 Link 中发送“schema”,但如果这完全取代了媒体类型参数,可能会影响媒体类型语义和 Content-Type 协商

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

                    

11.3. 通过 HTTP 使用

当用于网络上的超媒体系统时,HTTP 通常是用于分发模式的首选协议。如果恶意客户端比必要时更频繁地从网络上提取模式,而不是将模式缓存很长时间,则会导致服务器维护人员遇到问题。

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

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

                        

客户端应该设置或在特定于 JSON 模式实现或软件产品的 User-Agent 标头前添加。由于符号按重要性降序排列,因此 JSON 模式库名称/版本应该在更通用的 HTTP 库名称(如果有)之前。例如

客户端应该能够使用“From”标头发出请求,以便服务器运营商可以联系可能存在错误脚本的所有者。

12. 安全注意事项

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

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

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

各个 JSON 模式词汇表也可能具有其自身的安全注意事项。请参阅相应的规范以获取更多信息。

模式作者应该注意“$comment”内容,因为恶意实现可以违反规范将其显示给最终用户,或者如果预期这种行为则无法将其删除。

恶意模式作者可以在“$comment”中放置可执行代码或其他危险材料。实现绝对不能解析或根据“$comment”内容采取其他行动。

13. IANA 注意事项

13.1. application/schema+json

提议的 JSON 模式 MIME 媒体类型定义如下

13.2. application/schema-instance+json

提议的 MIME 媒体类型用于需要 JSON 模式特定媒体类型的 JSON 模式实例定义如下

14. 参考资料

14.1. 规范性引用

[ecma262] "ECMA 262 规范"
[RFC2119] Bradner, S.,"RFC 中用于指示需求级别的关键词",BCP 14,RFC 2119,DOI 10.17487/RFC2119,1997 年 3 月。
[RFC3986] Berners-Lee, T.Fielding, R.L. Masinter,"统一资源标识符 (URI):通用语法",STD 66,RFC 3986,DOI 10.17487/RFC3986,2005 年 1 月。
[RFC6839] Hansen, T.A. Melnikov,"附加媒体类型结构化语法后缀",RFC 6839,DOI 10.17487/RFC6839,2013 年 1 月。
[RFC6901] Bryan, P.Zyp, K.M. Nottingham,"JavaScript 对象表示法 (JSON) 指针",RFC 6901,DOI 10.17487/RFC6901,2013 年 4 月。
[RFC8259] Bray, T.,"JavaScript 对象表示法 (JSON) 数据交换格式",STD 90,RFC 8259,DOI 10.17487/RFC8259,2017 年 12 月。
[W3C.REC-ldp-20150226] Speicher, S.Arwe, J.A. Malhotra,"链接数据平台 1.0",万维网联盟推荐 REC-ldp-20150226,2015 年 2 月。

14.2. 信息性引用

[json-hyper-schema] Andrews, H.A. Wright,"JSON 超级模式:用于 JSON 超媒体注释的词汇表",互联网草案 draft-handrews-json-schema-hyperschema-02,2017 年 11 月。
[json-schema-validation] Wright, A.Andrews, H.G. Luff,"JSON 模式验证:用于 JSON 结构验证的词汇表",互联网草案 draft-handrews-json-schema-validation-02,2017 年 11 月。
[RFC6596] Ohye, M.J. Kupke,"规范链接关系",RFC 6596,DOI 10.17487/RFC6596,2012 年 4 月。
[RFC7049] Bormann, C.P. Hoffman,"简洁二进制对象表示 (CBOR)",RFC 7049,DOI 10.17487/RFC7049,2013 年 10 月。
[RFC7231] Fielding, R.J. Reschke,"超文本传输协议 (HTTP/1.1):语义和内容",RFC 7231,DOI 10.17487/RFC7231,2014 年 6 月。
[RFC8288] Nottingham, M.,"Web 链接",RFC 8288,DOI 10.17487/RFC8288,2017 年 10 月。
[W3C.WD-fragid-best-practices-20121025] Tennison, J.,"片段标识符和媒体类型定义的最佳实践",万维网联盟 WD WD-fragid-best-practices-20121025,2012 年 10 月。

附录 A. 模式标识示例

考虑以下模式,它显示“$id”用于标识根模式和各种子模式,以及“$anchor”用于定义纯名称片段标识符。

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

                

以下 URI 编码的 JSON 指针(相对于根模式)处的模式具有以下基本 URI,并且根据第 5 节和第 8.2.2.2 节的规定,可以通过任何列出的 URI 标识。

# (文档根)
规范绝对 URI(也是基本 URI)
https://example.com/root.json
带指针片段的规范 URI
https://example.com/root.json#

#/$defs/A
基本 URI
https://example.com/root.json
带纯片段的规范 URI
https://example.com/root.json#foo
带指针片段的规范 URI
https://example.com/root.json#/$defs/A

#/$defs/B
基本 URI
https://example.com/other.json
带指针片段的规范 URI
https://example.com/other.json#
相对于 root.json 的非规范 URI 带片段
https://example.com/root.json#/$defs/B

#/$defs/B/$defs/X
基本 URI
https://example.com/other.json
带纯片段的规范 URI
https://example.com/other.json#bar
带指针片段的规范 URI
https://example.com/other.json#/$defs/X
相对于 root.json 的非规范 URI 带片段
https://example.com/root.json#/$defs/B/$defs/X

#/$defs/B/$defs/Y
基本 URI
https://example.com/t/inner.json
带纯片段的规范 URI
https://example.com/t/inner.json#bar
带指针片段的规范 URI
https://example.com/t/inner.json#
相对于 other.json 的非规范 URI 带片段
https://example.com/other.json#/$defs/Y
相对于 root.json 的非规范 URI 带片段
https://example.com/root.json#/$defs/B/$defs/Y

#/$defs/C
基本 URI
urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f
带指针片段的规范 URI
urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f#
相对于 root.json 的非规范 URI 带片段
https://example.com/root.json#/$defs/C

附录 B. 操作模式文档和引用

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

B.1. 将模式资源捆绑到单个文档中

旨在一起使用的模式资源集可以组织为每个资源都在其自己的模式文档中,所有资源都在同一个模式文档中,或者介于两者之间的任何文档分组粒度。

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

只要所有静态引用(例如 "$ref")使用解析为规范 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/2019-09/schema",
    "$id": "https://example.com/tree",
    "$recursiveAnchor": true,

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

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

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

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

                

如果我们将 "strict-tree" 模式应用于实例,我们将遵循 "$ref" 到 "tree" 模式,检查其 "children" 子模式,并在其 "items" 子模式中找到 "$recursiveAnchor"。此时,动态路径为 "#/$ref/properties/children/items/$recursiveRef"。

此时的基本 URI 为 "https://example.com/tree",因此 "$recursiveRef" 最初解析为 "https://example.com/tree#"。由于 "$recursiveAnchor" 为真,因此我们检查动态路径以查看是否要使用不同的基本 URI。我们在 "#" 和 "#/$ref" 的动态路径中找到值为真的 "$recursiveAnchor"。

最外层是 "#",它是 "strict-tree" 模式 的根模式,因此我们使用其基本 URI "https://example.com/strict-tree",它为 "$recursiveRef" 生成最终解析的 URI "https://example.com/strict-tree#"。

这样,"tree" 模式中的递归将递归到 "strict-tree" 的根,而不是仅将 "strict-tree" 应用于实例根,而是将 "tree" 应用于实例子节点。

附录 D. 使用词汇表

D.1. 词汇表和元模式作者的最佳实践

词汇表作者应注意避免关键字名称冲突,如果词汇表旨在广泛使用,并且可能与其他词汇表组合使用。JSON Schema 没有提供任何正式的命名空间系统,但也没有限制关键字名称,允许使用任意数量的命名空间方法。

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

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

词汇表作者应该提供一个元模式,用于验证词汇表关键字在它们自身上的预期用法。此类元模式不应禁止其他关键字,并且不应禁止核心词汇表中的任何关键字。

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

元模式的递归性质使得 "$recursiveAnchor" 和 "$recursiveRef" 关键字特别适用于扩展现有的元模式,如 JSON 超级模式元模式扩展验证元模式所示。

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

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

仅供本地使用的元模式,无需在任意实现中测试词汇表支持,可以安全地完全省略 "$vocabulary"。

D.2. 带有词汇表声明的元模式示例

此元模式显式声明了核心和应用器词汇表,以及扩展词汇表,并将它们的元模式与 "allOf" 组合在一起。扩展词汇表的元模式仅描述该词汇表中的关键字,它显示在主示例元模式之后。

主示例元模式还通过禁止以 "unevaluated" 为前缀的关键字来限制应用器词汇表的用法,这些关键字在实现方面特别复杂。这不会更改应用器词汇表定义的语义或关键字集。它只是确保使用此元模式的尝试使用以 "unevaluated" 为前缀的关键字的模式将无法通过此元模式的验证。

最后,此元模式描述了一个关键字 "localKeyword" 的语法,该关键字不属于任何词汇表。据推测,此元模式的实现者和用户将理解 "localKeyword" 的语义。JSON Schema 没有定义任何机制来表达词汇表之外的关键字语义,使其不适合在除特定环境之外的环境中使用,这些环境理解它们。

此元模式组合了几个用于一般用途的词汇表。

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

                    

此元模式仅描述单个扩展词汇表。

{
  "$schema": "https://json-schema.fullstack.org.cn/draft/2019-09/schema",
  "$id": "https://example.com/meta/example-vocab",
  "$recursiveAnchor": true,
  "$vocabulary": {
    "https://example.com/vocab/example-vocab": true,
  },
  "type": ["object", "boolean"],
  "properties": {
    "minDate": {
      "type": "string",
      "pattern": "\d\d\d\d-\d\d-\d\d",
      "format": "date",
    }
  }
}

                    

如上所示,即使一般用途元模式的 "allOf" 中引用的每个单词汇表元模式都声明了其相应的词汇表,但此新元模式必须重新声明它们。

组合了核心和验证规范定义的所有词汇表的标准元模式,以及组合了这些规范以及超级模式规范定义的所有词汇表的标准元模式,展示了其他复杂的组合。这些元模式的 URI 分别可以在验证和超级模式规范中找到。

虽然一般用途元模式可以验证 "minDate" 的语法,但词汇表定义了 "minDate" 语义含义背后的逻辑。在不理解语义的情况下(在本例中,实例值必须等于或晚于作为关键字值在模式中提供的日期),实现只能验证语法用法。在本例中,这意味着验证它是否是一个日期格式的字符串(使用 "pattern" 来确保即使 "format" 函数纯粹作为注释进行验证,如 验证规范 中所述)。

附录 E. 引用和生成性用例

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

为了使此类用例特定的语义明确,最佳实践是在同一个模式对象中与引用关键字(如 "$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、Ben Hutton、Evgeny Poberezkin、Brad Bowman、Gowry Sankar、Donald Pipowitch 和 Dave Finlay 对文档的提交和修补。

附录 G. 变更日志

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

draft-handrews-json-schema-02

draft-handrews-json-schema-01

draft-handrews-json-schema-00

draft-wright-json-schema-01

draft-wright-json-schema-00

draft-zyp-json-schema-04

draft-zyp-json-schema-00

作者地址

奥斯汀·赖特 (编辑) 电子邮件: [email protected]
亨利·安德鲁斯 (编辑) 电子邮件: [email protected]
本·哈顿 (编辑) 惠康桑格研究所 电子邮件: [email protected] URI: https://jsonschema.dev
格雷格·丹尼斯 奥克兰, 新西兰 电子邮件: [email protected]