互联网工程任务组 | A. Wright,编辑 |
互联网草案 | |
预期状态:信息 | H. Andrews,编辑 |
失效日期:2020 年 3 月 20 日 | |
B. Hutton,编辑 | |
Wellcome Sanger 研究所 | |
G. Dennis | |
2019 年 9 月 17 日 |
JSON Schema:用于描述 JSON 文档的媒体类型
draft-handrews-json-schema-02
JSON Schema 定义了媒体类型“application/schema+json”,这是一种基于 JSON 的格式,用于描述 JSON 数据的结构。JSON Schema 声明 JSON 文档应该是什么样子,提取信息的方法以及如何与之交互。“application/schema-instance+json”媒体类型提供了比“application/json”文档可以提供的更丰富的与“application/schema+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/。
互联网草案是工作文档,有效期最长为六个月,并且可能随时更新、替换或被其他文档废弃。不建议将互联网草案作为参考资料,也不建议引用它们,除非作为“正在进行的工作”。
本互联网草案将于 2020 年 3 月 20 日失效。
版权所有 (c) 2019 IETF 信托和本文档作者。版权所有。
本文档受 BCP 78 和 IETF 信托的《与 IETF 文档相关的法律条款》(https://trustee.ietf.org/license-info)的约束,该条款在本文档发布之日生效。请仔细阅读这些文档,因为它们描述了您对本文档的权利和限制。从本文档中提取的代码组件必须包含简化 BSD 许可证文本,如信托法律条款第 4.e 节所述,并且按简化 BSD 许可证中所述的方式提供,不附带任何保证。
JSON Schema 是一种用于定义 JSON 数据结构的 JSON 媒体类型。JSON Schema 用于定义 JSON 数据的验证、文档、超链接导航和交互控制。
本规范定义了 JSON Schema 核心术语和机制,包括通过引用指向另一个 JSON Schema,反引用 JSON Schema 引用,指定使用的词汇表以及定义预期输出。
其他规范定义了执行关于验证、链接、注释、导航和交互的断言的词汇表。
本文档中的关键词“必须”、“禁止”、“必需”、“应”、“不应”、“建议”、“不建议”、“推荐”、“可以”和“可选”应按 RFC 2119 中的描述进行解释。
本文档中的术语“JSON”、“JSON 文本”、“JSON 值”、“成员”、“元素”、“对象”、“数组”、“数字”、“字符串”、“布尔值”、“真”、“假”和“空值”应按 RFC 8259 中的定义进行解释。
本文档提出了一种新的媒体类型“application/schema+json”,用于识别用于描述 JSON 数据的 JSON Schema。它还提出了一种可选的媒体类型“application/schema-instance+json”,以提供额外的集成功能。JSON Schema 本身就是 JSON 文档。本规范及其相关规范定义了关键字,允许作者以多种方式描述 JSON 数据。
JSON Schema 使用关键字对 JSON 实例施加约束或用附加信息对其进行注释。其他关键字用于将断言和注释应用于更复杂的 JSON 数据结构,或基于某种条件。
为了便于重复使用,关键字可以组织成词汇表。词汇表由一个关键字列表组成,以及它们的语法和语义。
JSON Schema 可以通过定义额外的词汇表来扩展,也可以通过在任何词汇表之外定义额外的关键字来非正式地扩展。无法识别的单个关键字将被忽略,而关于无法识别的词汇表的行为可以在声明使用哪些词汇表时进行控制。
本文档定义了一个核心词汇表,任何实现都必须支持该词汇表,并且不能禁用它。它的每个关键字都以“$”字符为前缀,以强调它们是必需的。这个词汇表对于“application/schema+json”媒体类型的功能至关重要,并用于引导其他词汇表的加载。
此外,本文档定义了推荐的关键字词汇表,用于有条件地应用子 Schema,以及将子 Schema 应用于对象和数组的内容。无论是用于断言验证、注释还是两者兼而有之,要编写非平凡的 JSON 实例的 Schema,都需要此词汇表或非常类似的词汇表。虽然不是必需的核心词汇表的一部分,但为了最大限度地实现互操作性,本规范中包含了此词汇表,并强烈建议使用它。
用于结构验证或超媒体注释等目的的更多词汇表在其他文档中定义。
JSON 文档是 application/json 媒体类型描述的信息资源(一系列字节)。
在 JSON Schema 中,由于它定义的数据模型,术语“JSON 文档”、“JSON 文本”和“JSON 值”可以互换。
JSON Schema 仅针对 JSON 文档定义。但是,任何可以解析为或根据 JSON Schema 数据模型处理的文档或内存结构都可以与 JSON Schema 进行解释,包括像 CBOR 这样的媒体类型。
应用 Schema 的 JSON 文档称为“实例”。
JSON Schema 根据数据模型解释文档。根据此数据模型解释的 JSON 值称为“实例”。
实例具有六种基本类型之一,并且根据类型具有多种可能的取值范围
空白和格式问题,包括在数据模型中相等的数字的不同词法表示,因此不在 JSON Schema 的范围之内。希望处理这种词法表示差异的 JSON Schema 词汇表 应该定义关键词来精确地解释数据模型中的格式化字符串,而不是依赖于原始 JSON 表示的 Unicode 字符可用。
由于一个对象不能有两个具有相同键的属性,因此对于尝试在单个对象中定义两个具有相同键(“string” 产生式)的属性(“member” 产生式)的 JSON 文档,其行为是未定义的。
请注意,JSON Schema 词汇表可以自由定义自己的扩展类型系统。这与这里定义的核心数据模型类型不应混淆。例如,“integer” 是词汇表可以定义为关键词值的合理类型,但数据模型没有区分整数和其他数字。
JSON Schema 旨在与 “application/json” 文档以及使用 “+json” 结构化语法后缀的媒体类型完全协同工作。
与模式一起工作的一些有用功能由每个媒体类型定义,即媒体类型参数以及 URI 片段标识符语法和语义。这些特性分别在内容协商和计算实例内特定位置的 URI 时很有用。
本规范定义了 “application/schema-instance+json” 媒体类型,以便允许实例作者充分利用参数和片段标识符来实现这些目的。
当且仅当两个 JSON 实例具有相同的类型并且根据数据模型具有相同的值时,它们被认为是相等的。具体来说,这意味着
此定义中隐含的是,数组必须具有相同的长度,对象必须具有相同数量的成员,对象中的属性是无序的,无法定义具有相同键的多个属性,并且仅格式差异(缩进、逗号位置、尾随零)是不重要的。
JSON Schema 文档,或简称为模式,是一个用于描述实例的 JSON 文档。模式本身可以解释为一个实例,但应该始终被赋予媒体类型 “application/schema+json” 而不是 “application/schema-instance+json”。“application/schema+json” 媒体类型被定义为提供 “application/schema-instance+json” 提供的媒体类型参数和片段标识符语法和语义的超集。
JSON Schema 必须是一个对象或一个布尔值。
应用于实例的对象属性称为关键词或模式关键词。从广义上讲,关键词分为以下四类
关键词可能属于多个类别,但应用器应该仅基于其子模式的结果产生断言结果。它们不应定义与其子模式无关的额外约束。
扩展关键词,即在本文档及其配套文档之外定义的关键词,可以自由定义其他行为。
JSON Schema 可以包含不是模式关键词的属性。未知关键词应该被忽略。
空模式是一个没有属性或只有未知属性的 JSON Schema。
布尔模式值 “true” 和 “false” 是始终产生自身作为断言结果的简单模式,与实例值无关。它们永远不会产生注释结果。
这些布尔模式是为了阐明模式作者的意图并促进模式处理优化而存在的。它们的行为与以下模式对象相同(其中 “not” 是在本文档中定义的子模式应用词汇表的一部分)。
虽然空模式对象是明确的,但存在许多与 “false” 模式等效的模式。使用布尔值确保对于人类读者和实现来说意图都是清晰的。
模式词汇表,或简称为词汇表,是一组关键词、它们的语法和它们的语义。词汇表通常围绕特定目的进行组织。JSON Schema 的不同用途,如验证、超媒体或用户界面生成,将涉及不同的词汇表集。
词汇表是 JSON Schema 中的主要重用单位,因为模式作者可以指示处理模式时哪些词汇表是必需的或可选的。由于词汇表在元模式中通过 URI 标识,因此通用实现可以加载扩展以支持以前未知的词汇表。虽然关键词可以在任何词汇表之外得到支持,但没有类似的机制来指示单个关键词的使用情况。
一个本身描述模式的模式称为元模式。元模式用于验证 JSON 模式并指定它们使用的词汇表。
通常,元模式将指定一组词汇表,并验证符合这些词汇表语法的模式。但是,元模式和词汇表是分开的,以便允许元模式比词汇表规范要求的更严格或更宽松地验证模式一致性。元模式还可以描述和验证不是正式词汇表一部分的额外关键词。
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 文档中,它也将是一个文档根模式。
根据 [RFC6839] 的第 3.1 节,为任何 +json 媒体类型指定的片段标识符的语法和语义应与 “application/json” 中指定的相同。(在本文档发布时,尚未为 “application/json” 定义片段标识语法。)
此外,“application/schema+json” 媒体类型支持两种片段标识符结构:普通名称和 JSON 指针。“application/schema-instance+json” 媒体类型支持一种片段标识符结构:JSON 指针。
JSON 指针作为 URI 片段标识符的使用在 RFC 6901 中描述。对于支持两种片段标识符语法的 “application/schema+json”,包括空字符串在内的与 JSON 指针语法匹配的片段标识符必须解释为 JSON 指针片段标识符。
根据 W3C 的 片段标识符最佳实践,“application/schema+json” 中的普通名称片段标识符保留用于引用本地命名的模式。所有不匹配 JSON 指针语法的片段标识符必须解释为普通名称片段标识符。
在 “application/schema+json” 文档中定义和引用普通名称片段标识符在 “$anchor” 关键词 部分中指定。
实例可以是 JSON 定义的任何有效 JSON 值。JSON Schema 对类型没有限制:JSON Schema 可以描述任何 JSON 值,包括例如 null。
JSON Schema 与编程语言无关,并支持数据模型中描述的全部值范围。但是,请注意,某些语言和 JSON 解析器可能无法在内存中表示 JSON 可描述的全部值范围。
某些编程语言和解析器使用与整数不同的内部表示来表示浮点数。
为了保持一致性,整数 JSON 数字不应使用小数部分编码。
关键词可以使用正则表达式来表达约束,或将实例值约束为正则表达式。这些正则表达式应该根据 ECMA 262,第 15.10.1 节 中描述的正则表达式方言有效。
此外,鉴于正则表达式构造支持方面的巨大差异,模式作者应该将自己限制在以下正则表达式标记中
最后,实现不应将正则表达式视为锚定,无论是开头还是结尾。这意味着,例如,模式 “es” 匹配 “expression”。
任何实体都可以定义额外的模式关键词和模式词汇表。除了明确协议外,模式作者不应期望这些额外的关键词和词汇表得到未明确记录此类支持的实现的支持。实现应忽略它们不支持的关键词。
实现 MAY 提供注册或加载其不支持的词汇表的处理程序的功能。注册和实现此类处理程序的确切机制取决于实现。
JSON Schema 关键字分为几个常见的行为类别。断言验证实例是否满足约束,并产生布尔值结果。注释附加应用程序可随意使用的信息。应用器将子模式应用于实例的各个部分,并组合其结果。
扩展关键字 SHOULD 保持在这些类别中,牢记注释尤其灵活。复杂的行为通常最好委托应用程序根据注释数据执行,而不是直接作为模式关键字实现。但是,扩展关键字 MAY 为特定目的定义其他行为。
根据模式评估实例涉及处理模式中的所有关键字,针对实例内的适当位置进行处理。通常,应用器关键字会一直处理,直到达到没有应用器(因此没有子模式)的模式对象为止。将实例中的适当位置根据模式对象中的断言和注释关键字进行评估,并将它们的结果根据应用器的规则收集到父模式中。
一旦所有子模式都被评估,父模式对象的评估就可以完成,尽管在某些情况下,由于断言结果,评估可能被短路。当收集注释时,某些断言结果短路是不可能的,因为需要检查所有子模式以进行注释收集,包括那些无法进一步更改断言结果的子模式。
虽然大多数 JSON Schema 关键字可以独立评估,或者最多需要考虑同一模式对象中相邻关键字的值或结果,但有一些关键字的行为更复杂。
关键字的词法范围由对象和数组的嵌套 JSON 数据结构确定。最大的范围是整个模式文档。最小的范围是单个模式对象,没有子模式。
关键字 MAY 被定义为具有部分值,例如 URI 引用,该值必须相对于另一个值解析,例如另一个 URI 引用或完整 URI,该值是通过 JSON 文档的词法结构找到的。"$id" 核心关键字和 "base" JSON 超级模式关键字是此类行为的示例。此外,本规范中的 "$ref" 和 "$recursiveRef" 以这种方式解析它们的值,尽管它们不会改变后续值的解析方式。
请注意,某些关键字,例如 "$schema",适用于整个模式文档的词法范围,因此 MUST 只出现在模式资源的根模式中。
其他关键字可能需要考虑在评估模式期间存在的动态范围,通常与实例文档一起存在。最外层的动态范围是开始处理的模式文档的根模式。从该根模式到任何特定关键字的路径(包括可能已解析的任何 "$ref" 和 "$recursiveRef" 关键字)被认为是关键字的 "验证路径"。 [CREF1]或者应该是在此开始处理的模式对象,即使它不是根?这对 "$recursiveAnchor" 仅允许在根模式中出现但处理从子模式开始的情况有一些影响。
词法范围和动态范围一致,直到遇到引用关键字。虽然遵循引用关键字将处理从一个词法范围移动到另一个词法范围,但从动态范围的角度来看,遵循引用与下降到作为值的子模式没有区别。该引用远端的关键字,它通过动态范围解析信息,将把引用的起始端视为其动态父级,而不是检查本地词法封闭父级。
动态范围的概念主要用于 "$recursiveRef" 和 "$recursiveAnchor",应被视为高级功能,并在定义附加关键字时谨慎使用。它也出现在报告错误和收集的注释时,因为可能重复地访问相同的词法范围,但使用不同的动态范围。在这种情况下,重要的是告知用户生成错误或注释的动态路径。
关键字行为 MAY 以 子模式 和/或相邻关键字的注释结果来定义。此类关键字 MUST NOT 导致循环依赖。关键字 MAY 根据另一个关键字在同一 模式对象 中是否存在来修改其行为。
缺少的关键字 MUST NOT 产生错误的断言结果,MUST NOT 产生注释结果,并且 MUST NOT 导致任何其他模式作为其自身行为定义的一部分进行评估。但是,考虑到缺少的关键字不会贡献注释,因此缺乏注释结果可能会间接更改其他关键字的行为。
在某些情况下,缺少关键字断言行为与特定值产生的行为相同,关键字定义 SHOULD 在已知的情况下记录此类值。但是,即使产生默认行为的值如果存在会产生注释结果,默认行为仍然 MUST NOT 导致注释。
由于注释收集在计算和内存方面都会增加显著成本,因此实现 MAY 选择不使用此功能。实现已知具有依赖注释结果的断言或应用器行为的关键字 MUST 然后被视为错误,除非存在产生相同行为的替代实现。此类关键字 SHOULD 在适当的情况下描述合理的替代方法。本文件中 "additionalItems" 和 "additionalProperties" 关键字演示了这种方法。
标识符设置模式的规范 URI,或者影响此类 URI 在 引用 中的解析方式,或者两者兼而有之。本文件中定义的核心词汇定义了几个标识关键字,最值得注意的是 "$id"。
规范模式 URI MUST NOT 在处理实例期间更改,但影响 URI 引用解析的关键字 MAY 具有仅在运行时才能完全确定的行为。
虽然自定义标识符关键字是可能的,但词汇表设计人员应该注意不要破坏核心关键字的功能。例如,本规范中的 "$recursiveAnchor" 关键字将其 URI 解析效果限制在匹配的 "$recursiveRef" 关键字中,使 "$ref" 不受干扰。
应用器允许构建比使用单个模式对象所能实现的更复杂的模式。根据 模式文档 评估实例,首先将 根模式 应用于完整的实例文档。从那里,称为应用器的关键字用于确定应用哪些附加模式。这些模式可以就地应用于当前位置,也可以应用于子位置。
要应用的模式可以作为构成关键字值全部或部分的子模式存在。或者,应用器可以引用同一模式文档或不同模式文档中的其他位置的模式。用于识别此类引用模式的机制由关键字定义。
应用器关键字还定义了如何修改和/或组合子模式或引用模式布尔 断言 结果,以产生应用器的布尔值结果。应用器可以将任何布尔逻辑运算应用于子模式的断言结果,但 MUST NOT 引入自己的新断言条件。
注释 结果根据每个注释关键字指定的规则进行组合。
如 第 7.5 节 所述,应用器关键字可以引用要应用的模式,而不是将其作为子模式包含在应用器值中。在这种情况下,要应用的模式称为引用模式,而包含应用器关键字的模式称为引用模式。
虽然根模式和子模式是基于模式在模式文档中的位置的静态概念,但引用和引用模式是动态的。在根据模式评估实例期间,不同的模式对可能发现自己处于各种引用和引用排列中。
对于某些按引用应用器,例如 "$ref",引用模式可以通过对模式文档的词法范围进行静态分析来确定。其他应用器,例如 "$recursiveRef" 和 "$recursiveAnchor",可能利用动态范围,因此只有在使用实例评估模式的过程中才能解析。
JSON Schema 可用于断言 JSON 文档的约束,该文档要么通过断言,要么失败。这种方法可用于验证对约束的符合性,或记录满足约束所需的条件。
JSON Schema 实现根据实例对模式断言的评估产生单个布尔值结果。
实例只能失败模式中存在的断言。
大多数断言只约束特定基本类型中的值。当实例的类型不是关键字目标的类型时,实例被认为符合断言。
例如,配套 验证词汇表 中的 "maxLength" 关键字:只会限制某些字符串(太长)有效。如果实例是数字、布尔值、空值、数组或对象,那么它对于此断言来说就是有效的。
此行为允许更轻松地将关键字与可以具有多种基本类型的实例一起使用。配套验证词汇表还包含一个 "type" 关键字,它可以独立地将实例限制为一个或多个基本类型。这允许以简洁的方式表达用例,例如可能返回特定长度的字符串或空值的函数
{ "type": ["string", "null"], "maxLength": 255 }
如果 "maxLength" 还将实例类型限制为字符串,那么这将更加繁琐地表达,因为按编写方式的示例实际上不允许空值。每个关键字都独立评估,除非明确说明否则,因此如果 "maxLength" 将实例限制为字符串,那么在 "type" 中包含 "null" 将没有任何有用的效果。
JSON Schema 可以用信息来注释实例,只要实例验证通过包含注释的模式对象及其所有父模式对象即可。信息可以是一个简单值,也可以根据实例内容计算得出。
注释附加到实例中的特定位置。由于许多子模式可以应用于任何单个位置,因此注释关键字需要指定对多个具有不同值的关键字应用实例的任何不寻常处理。
与断言结果不同,注释数据可以采用多种形式,这些形式提供给应用程序随意使用。JSON Schema 实现不需要代表应用程序使用收集的信息。
除非另有说明,否则注释关键字的注释的值是关键字的值。但是,其他行为也是可能的。例如,JSON 超级模式 的 "links" 关键字是一种复杂的注释,它根据实例数据产生一个值。
尽管断路评估可以用于断言,但收集注释需要检查应用于实例位置的所有模式,即使它们无法改变整体断言结果。唯一的例外是,如果一个模式对象验证失败,则可以跳过该模式对象的子模式,因为不会为失败的模式保留注释。
注释是通过显式定义注释收集行为的关键字收集的。请注意,布尔模式无法生成注释,因为它们不使用关键字。
收集的注释必须包含以下信息:
如果同一个关键字将来自多个模式位置的值附加到同一个实例位置,并且注释定义了组合这些值的流程,则组合的值也必须与实例位置相关联。本规范中描述的包含注释信息的输出格式满足此要求。
应用程序可以根据贡献值的模式位置来决定使用哪些多个注释值。这是为了允许灵活使用。收集模式位置有助于这种使用。
例如,考虑以下模式,它使用来自 验证规范 的注释和断言。
请注意,为了清晰起见,某些行被换行。
{ "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" 存在两个不同的值都属于错误。
生成 false 断言结果的模式对象不得生成任何注释结果,无论是来自它们自己的关键字,还是来自子模式中的关键字。
请注意,总体模式结果可能仍包含从其他模式位置收集的注释。假设有以下模式:
{ "oneOf": [ { "title": "Integer Value", "type": "integer" }, { "title": "String Value", "type": "string" } ] }
以及实例 "This is a string",则标题注释 "Integer Value" 被丢弃,因为该模式对象中的类型断言失败。标题注释 "String Value" 被保留,因为实例通过了字符串类型断言。
除了可能定义它们自己的注释结果外,应用器关键字还会聚合在其子模式或引用模式中收集的注释。聚合注释值的规则由每个注释关键字定义,并且不会直接受到用于组合断言结果的逻辑的影响。
第四类关键字只是保留一个位置来存放对模式作者而言是可重复使用组件或感兴趣数据的,但这些组件或数据不适合重复使用。这些关键字不会影响验证或注释结果。它们在核心词汇表中的作用是确保为某些目的保留位置,并且不会被扩展关键字重新定义。
尽管这些关键字不会直接影响结果,但正如第 8.2.4.4 节所述,用于保留可重复使用模式的位置的未识别的扩展关键字在某些情况下可能会与引用产生不利的交互。
本节中声明的关键字(均以 "$" 开头)构成了 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>.
尽管 "$" 前缀没有正式保留给核心词汇表,但建议扩展关键字(在词汇表中或其他位置)以非 "$" 开头的字符开头,以避免可能发生的未来冲突。
元模式和词汇表这两个概念用于告知实现如何解释模式。每个模式都有一个元模式,可以使用 "$schema" 关键字声明。
元模式有两个目的:
元模式独立于词汇表,以允许以不同的方式组合词汇表,并允许元模式作者施加额外的约束,例如禁止某些关键字,或执行异常严格的语法验证,例如在开发和测试周期中可能会进行的验证。每个词汇表通常会标识一个仅包含词汇表关键字的元模式。
元模式创作是 JSON 模式的先进用法,因此元模式功能的设计强调灵活性和简单性。
"$schema" 关键字既用作 JSON 模式功能集标识符,也用作资源标识符,该资源本身是一个 JSON 模式,描述了针对此特定功能集编写的有效模式集。
该关键字的值必须是 URI(包含一个方案),并且此 URI 必须是规范化的。当前模式必须针对此 URI 标识的元模式有效。
如果此 URI 标识一个可检索的资源,则该资源应为媒体类型 "application/schema+json"。
"$schema" 关键字应在资源根模式中使用。它不得出现在资源子模式中。如果从根模式中缺失,则结果行为由实现定义。
如果单个文档中存在多个模式资源,则所有模式资源应具有相同的值,以用于 "$schema"。同一个模式文档中 "$schema" 值不同的结果由实现定义。 [CREF2]在同一个文档中使用多个 "$schema" 关键字将意味着功能集(因此行为)可以在文档中发生改变。这将需要解决许多尚未明确定义的实现问题。因此,尽管使用 "$schema" 仅在根模式中的模式是可能仍然是模式创作的最佳实践,但实现行为可能会在未来的草案中进行修改或放宽。 [CREF3]对嵌入式模式资源的例外是为了允许将多个模式资源捆绑到一个模式文档中,而无需更改其内容,如本规范稍后所述。
此属性的值在本和其他文档中,以及其他方定义。
"$vocabulary" 关键字在元模式中使用,以识别可用于该元模式描述的模式的词汇表。它还用于指示每个词汇表是必需的还是可选的,即实现必须了解必需的词汇表才能成功处理模式。
该关键字的值必须是一个对象。对象中的属性名称必须是 URI(包含一个方案),并且此 URI 必须是规范化的。作为属性名称出现的每个 URI 标识一组特定的关键字及其语义。
URI 可以是 URL,但可检索资源的性质目前未定义,并保留供将来使用。词汇表作者可以使用词汇表规范的 URL(以人类可读的媒体类型,如 text/html 或 text/plain)作为词汇表 URI。 [CREF4]词汇表文档可能会在即将发布的草案中添加。目前,识别关键字集被认为足够,因为这以及元模式验证是当今 "词汇表" 的运作方式。任何未来的词汇表文档格式都将被指定为 JSON 文档,因此在此时使用 text/html 或其他非 JSON 格式不会产生任何未来的歧义。
对象属性的值必须是布尔值。如果值为真,则不识别词汇表的实现必须拒绝处理声明此元模式的任何模式,其"$schema"为真。如果值为假,则不识别词汇表的实现应该继续处理此类模式。
根据6.5,应忽略未识别的关键字。对于由未识别词汇表定义的关键字,情况仍然如此。目前无法区分在词汇表中定义的未识别关键字与不属于任何词汇表的未识别关键字。
"$vocabulary"关键字应在任何作为元模式使用的模式文档的根模式中使用。它不应出现在子模式中。
"$vocabulary"关键字在不作为元模式处理的模式文档中必须被忽略。这允许将元模式M验证到其自己的元模式M',而不需要验证器理解M声明的词汇表。
如果"$vocabulary"不存在,实现可以根据元模式确定行为,前提是它从引用模式的"$schema"关键字的URI值识别出来。这是在词汇表出现之前识别行为(例如Hyper-Schema使用)的方式。
如果模式引用的元模式不被识别,或丢失,则行为由实现定义。如果实现继续处理模式,则必须假设使用核心词汇表。如果实现是为特定目的而构建的,则应假设使用与该目的相关的最相关的词汇表。
例如,作为验证器的实现应假设使用本规范和配套验证规范中的所有词汇表。
请注意,"$vocabulary"的处理限制意味着使用"$ref"或类似关键字引用其他元模式的元模式不会自动继承这些其他元模式的词汇表声明。所有此类声明必须在每个作为元模式使用的模式文档的根中重复。这在元模式示例中进行了演示。 [CREF5]此要求允许实现找到每个元模式的单个位置的所有词汇表要求信息。由于模式的可扩展性意味着通过引用组合更细粒度的元模式有无限的可能性,因此要求实现预测所有可能性并在引用的元模式中搜索词汇表将过于繁重。
更新的词汇表和元模式URI可以在规范草案之间发布,以更正错误。实现应考虑此规范草案之后和下一个规范草案之前的日期的URI,以指示与此处列出的相同的语法和语义。
如果正在检查某个模式是因为它被另一个模式的"$schema"关键字识别为元模式,则实现必须将其识别为元模式。这意味着单个模式文档有时会被视为常规模式,而有时会被视为元模式。
在检查自身为元模式的模式的情况下,当实现开始将其作为常规模式处理时,它将在这些规则下进行处理。但是,当由于检查其自己的"$schema"值而第二次加载时,它将被视为元模式。因此,在一次会话中,同一文档将以两种方式进行处理。
实现可以允许将模式显式地传递为元模式,用于实现特定的目的,例如预加载常用的元模式并提前检查其词汇表支持要求。元模式作者不应期望此类功能在不同实现之间具有互操作性。
为了区分一个庞大生态系统中的模式,模式由URI标识,并且可以通过指定其URI来嵌入对其他模式的引用。
一些关键字可以接受相对URI-引用,或用于构建相对URI-引用的值。对于这些关键字,有必要建立一个基本URI来解析引用。
RFC3986 第 5.1 节定义了如何确定文档的默认基本URI。
信息性地,模式的初始基本URI是找到它的URI,无论它是网络位置、本地文件系统还是任何其他由任何已知方案的URI标识的情况。
如果模式文档没有使用"$id"(嵌入在内容中)定义任何显式基本URI,则基本URI是根据RFC 3986 第 5 节确定的。
如果不知道来源,或者不知道来源的URI方案,则可以使用RFC 3986 第 5.1.4 节中描述的适当的实现特定默认URI。建议实现记录它们假设的任何默认基本URI。
除非下一节描述的"$id"关键字存在于根模式中,否则此基本URI应被视为模式文档的根模式资源的规范URI。
"$id"关键字使用其规范URI标识模式资源。
请注意,此URI是一个标识符,不一定是网络定位符。在网络可寻址URL的情况下,模式不需要从其规范URI下载。
如果存在,此关键字的值必须是字符串,并且必须表示有效的URI-引用。此URI-引用应被规范化,并且必须解析为绝对URI(没有片段)。因此,"$id"不应包含非空的片段,并且不应包含空的片段。
由于在 application/schema+json 媒体类型上下文中,空的片段引用与没有片段的基本URI相同的资源,因此实现可以通过删除片段来规范以空片段结尾的URI。但是,模式作者不应依赖于不同实现之间的此行为。 [CREF6]这主要允许是因为旧的元模式在其 $id(或以前,id)中有一个空片段。未来的草案可能会完全禁止 "$id" 中的空片段。
此URI还用作模式资源内关键字中相对URI-引用的基本URI,符合RFC 3986 第 5.1.1 节关于嵌入在内容中的基本URI的规定。
"$id"在子模式中的存在表明子模式构成单个模式文档中的一个独立模式资源。此外,根据RFC 3986 第 5.1.2 节关于封装实体的规定,如果子模式中的"$id"是相对URI-引用,则解析该引用的基本URI是父模式资源的URI。
如果没有任何父模式对象明确地将自己标识为带有"$id"的资源,则基本URI是整个文档的URI,如上一节中给出的步骤所建立的。
JSON Schema 文档的根模式应包含一个"$id"关键字,其中包含一个绝对URI(包含一个方案,但不包含片段)。
由于 JSON 指针 URI 片段是根据模式文档的结构构建的,因此嵌入式模式资源及其子模式可以通过相对于其自身规范 URI 或相对于包含资源的 URI 的 JSON 指针片段来标识。
从概念上讲,一组链接的模式资源应该表现出相同的行为,无论每个资源是使用模式引用连接的独立文档,还是构建为单个文档,其中一个或多个模式资源嵌入为子模式。
由于涉及相对于父模式资源 URI 的 JSON 指针片段的 URI 在将嵌入式模式移动到独立文档并引用时不再有效,因此应用程序和模式不应使用此类 URI 来标识嵌入式模式资源或其中的位置。
请考虑以下包含另一个嵌入式模式资源的模式文档
{ "$id": "https://example.com/foo", "items": { "$id": "https://example.com/bar", "additionalProperties": { } } }
URI "https://example.com/foo#/items/additionalProperties" 指向嵌入式资源中 "additionalProperties" 关键字的模式。但是,该模式的规范 URI 是 "https://example.com/bar#/additionalProperties"。
现在考虑以下两个使用"$ref"的URI值通过引用链接的模式资源
{ "$id": "https://example.com/foo", "items": { "$ref": "bar" } } { "$id": "https://example.com/bar", "additionalProperties": { } }
在这里,我们看到该 "additionalProperties" 子模式的规范 URI 仍然有效,而以 "#/items/$ref" 开头的片段的非规范 URI 现在解析为空。
另请注意,"https://example.com/foo#/items" 在两种安排中都有效,但解析为不同的值。此 URI 最终的功能类似于资源的检索 URI。虽然有效,但检查解析的值,并使用 "$id"(如果该值是一个子模式),或解析引用并使用引用目标的 "$id",会更好。
实现可以选择不支持通过非规范 URI 寻址模式。因此,建议模式作者只使用规范 URI,因为使用非规范 URI 可能会降低模式的互操作性。 [CREF7]这样做是为了避免要求实现跟踪整个可能的基 URI 堆栈和每个 URI 的 JSON 指针片段,因为如果模式资源被重新组织,除了一个之外的所有 URI 都会很脆弱。有些人认为这很简单,因此没有必要禁止它,而另一些人则认为这会使模式识别复杂化,应该被禁止。鼓励对此主题的反馈。
此类非规范 URI 的更多示例,以及应该使用的适当规范 URI,在附录A 中提供。
使用 JSON 指针片段需要了解模式的结构。在编写旨在提供可重用模式的模式文档时,最好使用不与任何特定结构位置绑定的纯名称片段。这允许将子模式重新定位,而无需更新 JSON 指针引用。
"$anchor"关键字用于指定此类片段。它是一个标识符关键字,只能用于创建纯名称片段。
如果存在,此关键字的值 **必须** 是一个字符串,**必须** 以字母 ([A-Za-z]) 开头,后面可以跟任意数量的字母、数字 ([0-9])、连字符 ("-")、下划线 ("_")、冒号 (":") 或句点 ("."). [CREF8]请注意,锚字符串不包含 "#" 字符,因为它不是 URI 引用。一个 "$anchor": "foo" 在 URI 中使用时将变为片段 "#foo"。有关完整示例,请参见下文。
将生成的片段附加到的基本 URI 由 "$id" 关键字确定,如上一节所述。如果两个 "$anchor" 关键字应用于不同的基本 URI,则同一个模式文档中的两个 "$anchor" 关键字 **可以** 具有相同的值,因为生成的完整 URI 将是不同的。但是,具有相同值和相同基本 URI 的两个 "$anchor" 关键字的效果是未定义的。如果检测到此类用法,实现 **可以** 抛出错误。
可以使用多个关键字来引用要应用于当前实例位置的模式。"$ref" 和 "$recursiveRef" 是应用器关键字,将引用的模式应用于实例。"$recursiveAnchor" 是一个标识符关键字,控制如何确定解析 "$recursiveRef" 的 URI 引用值的基准 URI。
由于 "$ref" 和 "$recursiveRef" 的值是 URI 引用,因此这允许将模式跨多个文件外部化或划分,并提供通过自引用验证递归结构的能力。
这些关键字生成的解析后的 URI 不一定是网络定位器,而只是一个标识符。如果模式是一个可网络寻址的 URL,则不需要从地址下载模式,并且实现 **不应该** 假设在遇到可网络寻址的 URI 时应该执行网络操作。
"$ref" 关键字是一个应用器,用于引用静态标识的模式。其结果是引用模式的结果。 [CREF9]请注意,关于如何确定结果的这个定义意味着其他关键字可以与 "$ref" 一起出现在同一个模式对象中。
"$ref" 属性的值 **必须** 是一个字符串,该字符串是一个 URI 引用。相对于当前 URI 基准进行解析,它会生成要应用的模式的 URI。
"$recursiveRef" 和 "$recursiveAnchor" 关键字用于构建可扩展的递归模式。递归模式是指引用其自身根的模式,由空片段 URI 引用 ("#") 标识。
简而言之,"$recursiveRef" 的行为与 "$ref" 完全相同,除非其目标模式包含值为 true 的 "$recursiveAnchor"。在这种情况下,将检查动态作用域以确定新的基本 URI,并且 "$recursiveRef" 中的 URI 引用将针对该基本 URI 重新评估。与 "$id" 的基本 URI 更改不同,"$recursiveAnchor" 的更改是在每次解析 "$recursiveRef" 时计算的,并且不会影响任何其他关键字。
有关使用这些关键字的示例,请参见附录 C。 [CREF10]以前草案中的超模式元模式与本草案之间的差异显著地证明了这些关键字的效用。
"$recursiveRef" 属性的值 **必须** 是一个字符串,该字符串是一个 URI 引用。它是一个按引用应用器,它使用动态计算的基本 URI 来解析其值。
此关键字的行为仅针对值 "#" 定义。实现 **可以** 选择将其他值视为错误。 [CREF11]此限制将来可能会放宽,但到目前为止,只有值 "#" 有明确的用例。
"$recursiveRef" 的值最初针对当前基本 URI 进行解析,与 "$ref" 的方式相同。
检查由生成的 URI 标识的模式中是否存在 "$recursiveAnchor",并根据下一节中针对该关键字的描述计算新的基本 URI。
最后,"$recursiveRef" 的值针对根据 "$recursiveAnchor" 确定的新基本 URI 进行解析,生成最终解析的引用 URI。
请注意,在没有 "$recursiveAnchor" 的情况下(以及在某些情况下存在的情况下),"$recursiveRef" 的行为与 "$ref" 相同。
与 "$ref" 一样,此关键字的结果是引用模式的结果。
"$recursiveAnchor" 属性的值 **必须** 是一个布尔值。
"$recursiveAnchor" 用于在运行时通过标记可以开始和停止此类计算的位置,来动态识别 "$recursiveRef" 的基本 URI。此关键字 **不得** 影响其他关键字的基本 URI,除非明确定义为依赖于它。
如果设置为 true,则当包含模式对象用作 "$recursiveRef" 的目标时,将通过检查 动态作用域 以确定也包含值为 true 的 "$recursiveAnchor" 的最外部模式的基本 URI。然后,将该模式的基本 URI 用作动态基本 URI。
如果不存在此类模式,则基本 URI 保持不变。
如果此关键字设置为 false,则基本 URI 保持不变。
省略此关键字与值为 false 的行为相同。
模式 **不得** 对实例运行到无限循环中。例如,如果两个模式 "#alice" 和 "#bob" 都具有引用另一个模式的 "allOf" 属性,则一个简单的验证器可能会陷入无限递归循环中,试图验证实例。模式 **不应该** 使用这样的无限递归嵌套;行为是未定义的。
子模式对象(或布尔值)通过与已知应用器关键字或与保留位置的关键字(例如 "$defs",它将一个或多个子模式作为值)一起使用来识别。这些关键字可以是 "$defs" 和本文档中的标准应用器,或者来自已知词汇表的扩展关键字,或者特定于实现的自定义关键字。
未知关键字的多级结构能够引入嵌套子模式,这些子模式将受 "$id" 的处理规则约束。因此,无法可靠地实现此类未识别结构中的引用目标,并且生成的行为是未定义的。类似地,在已知关键字下,其值为已知不是模式的引用目标,会导致未定义的行为,以避免让实现承担检测此类目标的负担。 [CREF12]这些情况类似于通过 HTTP 获取模式,但接收到的响应的 Content-Type 不是 application/schema+json。实现当然可以尝试将其解释为模式,但源服务器没有保证它实际上是任何此类内容。因此,将其解释为模式存在安全隐患,并可能产生不可预测的结果。
请注意,语法和语义与 "$defs" 相同的单级自定义关键字不允许任何介入的 "$id" 关键字,因此在尝试使用任何引用目标作为模式的实现下,它们将表现正确。但是,此行为特定于实现,并且 **不得** 依赖于互操作性。
使用 URI 来识别远程模式并不一定意味着要下载任何东西,而是 JSON 模式实现 **应该** 提前了解将使用的模式以及标识它们的 URI。
当下载模式时,例如由不知道运行时要下载哪些模式的通用用户代理,请参阅 超媒体用法。
实现 **应该** 能够将任意 URI 与任意模式相关联,或者根据验证器对模式的信任程度自动将模式的 "$id" 给定的 URI 相关联。此类 URI 和模式可以在处理实例之前提供给实现,或者可以在处理模式文档时记录在模式文档中,生成附录 A 中所示的关联。
模式 **可以** (而且很可能会)具有多个 URI,但没有方法可以让 URI 标识多个模式。当多个模式尝试标识为同一个 URI 时,验证器 **应该** 抛出错误条件。
模式可以由赋予它们的任何 URI 识别,包括 JSON 指针或直接由 "$id" 给定的 URI。在所有情况下,取消引用 "$ref" 引用都涉及首先根据 RFC 3986 相对于当前基本 URI 解析其值作为 URI 引用。
如果生成的 URI 标识当前文档中的模式,或者标识已提供给实现的另一个模式文档中的模式,则 **应该** 自动使用该模式。
例如,考虑此模式
{ "$id": "https://example.net/root.json", "items": { "type": "array", "items": { "$ref": "#item" } }, "$defs": { "single": { "$anchor": "item", "type": "object", "additionalProperties": { "$ref": "other.json" } } } }
当实现遇到 <#/$defs/single> 模式时,它会相对于当前基本 URI 解析 "$id" URI 引用,形成 <https://example.net/root.json#item>。
当实现随后查看 <#/items> 模式内部时,它会遇到 <#item> 引用,并将其解析为 <https://example.net/root.json#item>,它已在此同一文档中定义,因此可以自动使用。
当实现遇到对 "other.json" 的引用时,它会将其解析为 <https://example.net/other.json>,该引用未在此文档中定义。如果已向实现提供具有该标识符的模式,则也可以自动使用它。 [CREF13]当引用模式未知时,实现应该怎么做?在哪些情况下允许自动网络取消引用?同一来源策略?用户可配置选项?在由超模式描述的不断发展的 API 的情况下,预计系统会动态添加新的模式,因此不可能绝对要求预加载模式文档。
"$defs" 关键字为模式作者保留一个位置,让他们将可重用的 JSON 模式内联到更通用的模式中。此关键字不会直接影响验证结果。
此关键字的值 **必须** 是一个对象。此对象的每个成员值 **必须** 是有效的 JSON 模式。
{ "type": "array", "items": { "$ref": "#/$defs/positiveInteger" }, "$defs": { "positiveInteger": { "type": "integer", "exclusiveMinimum": 0 } } }
例如,以下是一个描述正整数数组的模式,其中正整数约束是 "$defs" 中的子模式
此关键字为模式作者保留一个位置,用于向模式的读者或维护者添加注释。
此关键字的值 **必须** 是一个字符串。实现 **不得** 将此字符串呈现给最终用户。用于编辑模式的工具 **应该** 支持显示和编辑此关键字。此关键字的值 **可以** 在调试或错误输出中使用,这些输出是为使用模式的开发人员准备的。
模式词汇表 **应该** 允许在包含词汇表关键字的任何对象中使用 "$comment"。除非词汇表明确禁止使用 "$comment",否则实现 **可以** 假设允许使用 "$comment"。词汇表 **不得** 指定除本规范中描述的以外的 "$comment" 的任何效果。
将其他媒体类型或编程语言转换为 application/schema+json 的工具可以选择将该媒体类型或编程语言的原生注释转换为或从 "$comment" 值中转换。当原生注释和 "$comment" 属性都存在时,这种转换的行为取决于实现。
实现应该将 "$comment" 视为未知扩展关键字。它们可以在处理过程中的任何时候剥离 "$comment" 值。特别是,这允许在部署的模式大小是一个问题时缩短模式。
实现绝不能基于 "$comment" 属性的存在、不存在或内容采取任何其他行动。特别是,"$comment" 的值绝不能作为注释结果收集。
本节定义了应用器关键字的词汇表,建议将其用作其他词汇表的基础。
不使用 "$vocabulary" 的元模式应该被认为需要这个词汇表,就好像它的 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,以指示与此处列出的相同的语法和语义。
模式关键字通常独立运行,不会影响彼此的结果。
为了方便模式作者,此词汇表中的关键字之间存在一些例外。
这些关键字将子模式应用于与父模式正在应用的位置相同的实例位置。它们允许以各种方式组合或修改子模式结果。
这些关键字对应于用于组合或修改子模式的布尔断言结果的逻辑运算符。它们对注释收集没有直接影响,尽管它们允许将相同的注释关键字应用于具有不同值的实例位置。注释关键字定义了它们自己的规则来组合这些值。
此关键字的值必须是非空数组。数组的每个项目必须是一个有效的 JSON 模式。
如果实例成功验证了此关键字的值定义的所有模式,则它成功验证了此关键字。
此关键字的值必须是非空数组。数组的每个项目必须是一个有效的 JSON 模式。
如果实例成功验证了此关键字的值定义的至少一个模式,则它成功验证了此关键字。请注意,当收集注释时,必须检查所有子模式,以便从成功验证的每个子模式收集注释。
此关键字的值必须是非空数组。数组的每个项目必须是一个有效的 JSON 模式。
如果实例成功验证了此关键字的值定义的正好一个模式,则它成功验证了此关键字。
此关键字的值必须是一个有效的 JSON 模式。
如果实例未能成功验证此关键字定义的模式,则它对该关键字有效。
其中三个关键字协同工作,以根据另一个子模式的结果实现子模式的有条件应用。第四个是特定条件情况的快捷方式。
"if"、"then" 和 "else" 绝不能跨子模式边界相互交互。换句话说,一个 "allOf" 分支中的一个 "if" 绝不能影响另一个分支中的 "then" 或 "else"。
当 "if"、"then" 或 "else" 不存在时,它们没有默认行为。特别是,它们绝不能被视为存在于空模式中,当 "if" 不存在时,"then" 和 "else" 都必须完全被忽略。
此关键字的值必须是一个有效的 JSON 模式。
此关键字子模式的验证结果对整体验证结果没有直接影响。相反,它控制评估 "then" 或 "else" 关键字中的哪一个。
成功验证了此关键字子模式的实例也必须对 "then" 关键字的子模式值有效(如果存在)。
未能验证此关键字子模式的实例也必须对 "else" 关键字的子模式值有效(如果存在)。
如果正在收集注释,则按通常方式从此关键字子模式收集它们,包括当关键字存在但 "then" 或 "else" 不存在时。
此关键字的值必须是一个有效的 JSON 模式。
当 "if" 存在,并且实例成功验证了其子模式时,如果实例也成功验证了此关键字的子模式,则验证对该关键字成功。
当 "if" 不存在或实例未能验证其子模式时,此关键字无效。在这些情况下,实现绝不应针对此关键字评估实例,无论出于验证还是注释收集目的。
此关键字的值必须是一个有效的 JSON 模式。
当 "if" 存在,并且实例未能验证其子模式时,如果实例成功验证了此关键字的子模式,则验证对该关键字成功。
当 "if" 不存在或实例成功验证了其子模式时,此关键字无效。在这些情况下,实现绝不应针对此关键字评估实例,无论出于验证还是注释收集目的。
此关键字指定如果实例是对象并包含某个属性,则评估的子模式。
此关键字的值必须是一个对象。对象中的每个值必须是一个有效的 JSON 模式。
如果对象键是实例中的属性,则整个实例必须针对子模式进行验证。它的使用取决于该属性的存在。
省略此关键字与空对象具有相同的行为。
这些关键字中的每一个都定义了一个规则,用于将其子模式应用于子实例,特别是对象属性和数组项,并组合它们的结果。
"items" 的值必须是一个有效的 JSON 模式或一个有效的 JSON 模式数组。
如果 "items" 是一个模式,则如果数组中的所有元素成功验证了该模式,则验证成功。
如果 "items" 是一个模式数组,则如果实例的每个元素都验证了相同位置的模式(如果有),则验证成功。
此关键字生成一个注释值,该值是此关键字应用子模式的最大索引。如果子模式应用于实例的每个索引(例如 "items" 是一个模式时),则该值可以是布尔值 true。
来自应用于相同实例位置的多个模式的 "items" 关键字的注释结果通过将组合结果设置为 true(如果任何值都是 true),否则保留最大数值来组合。
省略此关键字与空模式具有相同的断言行为。
"additionalItems" 的值必须是一个有效的 JSON 模式。
此关键字的行为取决于同一模式对象中 "items" 的存在和注释结果。如果 "items" 存在,并且其注释结果是一个数字,则如果大于该数字的每个实例元素都验证了 "additionalItems",则验证成功。
否则,如果 "items" 不存在或其注释结果是布尔值 true,则必须忽略 "additionalItems"。
如果 "additionalItems" 子模式应用于实例数组中的任何位置,则它会生成一个布尔值 true 的注释结果,类似于 "items" 的单个模式行为。如果来自应用于相同实例位置的任何子模式的任何 "additionalItems" 关键字都生成一个值为 true 的注释值,那么来自这些关键字的组合结果也是 true。
省略此关键字与空模式具有相同的断言行为。
实现可以选择以另一种产生相同效果的方式实现或优化此关键字,例如通过直接检查 "items" 数组的存在和大小。不支持注释收集的实现必须这样做。
"unevaluatedItems" 的值必须是一个有效的 JSON 模式。
此关键字的行为取决于应用于正在验证的实例位置的相邻关键字的注释结果。具体来说,来自 "items" 和 "additionalItems" 的注释,它们可能来自这些关键字,当它们与 "unevaluatedItems" 关键字相邻时。这两个注释以及 "unevaluatedItems" 也可以来自任何和所有相邻的就地应用器关键字。这包括但不限于本文档中定义的就地应用器。
如果 "items" 注释存在,并且其注释结果是一个数字,并且不存在 "additionalItems" 或 "unevaluatedItems" 注释,则如果大于 "items" 注释的每个实例元素都验证了 "unevaluatedItems",则验证成功。
否则,如果任何 "items"、"additionalItems" 或 "unevaluatedItems" 注释存在且值为布尔值 true,则必须忽略 "unevaluatedItems"。但是,如果这些注释都不存在,则必须将 "unevaluatedItems" 应用于数组中的所有位置。
这意味着在评估此关键字之前,必须评估 "items"、"additionalItems" 和所有就地应用器。扩展关键字的作者绝不能定义需要在此关键字之前评估的就地应用器。
如果 "unevaluatedItems" 子模式应用于实例数组中的任何位置,则它会生成一个布尔值 true 的注释结果,类似于 "items" 的单个模式行为。如果来自应用于相同实例位置的任何子模式的任何 "unevaluatedItems" 关键字都生成一个值为 true 的注释值,那么来自这些关键字的组合结果也是 true。
省略此关键字与空模式具有相同的断言行为。
不支持注释收集的实现必须在遇到此关键字时引发错误。
此关键字的值必须是一个有效的 JSON 模式。
如果数组实例的至少一个元素对给定模式有效,则它对 "contains" 有效。请注意,在收集注释时,即使在找到第一个匹配项后,也必须将子模式应用于每个数组元素。这是为了确保收集所有可能的注释。
"properties" 的值必须是一个对象。此对象的每个值必须是一个有效的 JSON 模式。
如果对于在实例中和作为此关键字的值中的名称中都出现的每个名称,该名称的子实例都成功验证了相应的模式,则验证成功。
此关键字的注释结果是此关键字匹配的实例属性名称集合。应用于同一实例位置的多个模式中的“属性”关键字的注释结果通过获取集合的并集来合并。
省略此关键字与空对象具有相同的断言行为。
“patternProperties”的值必须是一个对象。此对象的每个属性名称应根据 ECMA 262 正则表达式方言为有效的正则表达式。此对象的每个属性值必须是有效的 JSON Schema。
如果对于每个与作为此关键字值中属性名称出现的任何正则表达式匹配的实例名称,该名称的子实例成功地针对与匹配的正则表达式相对应的每个模式进行验证,则验证成功。
此关键字的注释结果是此关键字匹配的实例属性名称集合。应用于同一实例位置的多个模式中的“patternProperties”关键字的注释结果通过获取集合的并集来合并。
省略此关键字与空对象具有相同的断言行为。
“additionalProperties”的值必须是有效的 JSON Schema。
此关键字的行为取决于同一模式对象中“属性”和“patternProperties”的存在和注释结果。使用“additionalProperties”进行的验证仅适用于实例名称的子值,这些子值未出现在“属性”或“patternProperties”的注释结果中。
对于所有此类属性,如果子实例针对“additionalProperties”模式进行验证,则验证成功。
此关键字的注释结果是此关键字子模式验证的实例属性名称集合。应用于同一实例位置的多个模式中的“additionalProperties”关键字的注释结果通过获取集合的并集来合并。
省略此关键字与空模式具有相同的断言行为。
实现可以自由选择以其他方式实现或优化此关键字,以产生相同的效果,例如,通过直接检查“属性”中的名称和“patternProperties”中的模式与实例属性集进行比较。不支持注释收集的实现必须这样做。
“unevaluatedProperties”的值必须是有效的 JSON Schema。
此关键字的行为取决于应用于正在验证的实例位置的相邻关键字的注释结果。具体而言,来自“属性”、“patternProperties”和“additionalProperties”的注释,这些注释可能来自这些关键字,当它们与“unevaluatedProperties”关键字相邻时。这三个注释以及“unevaluatedProperties”也可能来自任何和所有相邻的 就地应用器 关键字。这包括但不限于本文档中定义的就地应用器。
使用“unevaluatedProperties”进行的验证仅适用于实例名称的子值,这些子值未出现在应用于正在验证的实例位置的“属性”、“patternProperties”、“additionalProperties”或“unevaluatedProperties”注释结果中。
对于所有此类属性,如果子实例针对“unevaluatedProperties”模式进行验证,则验证成功。
这意味着“属性”、“patternProperties”、“additionalProperties”以及所有就地应用器必须在此关键字可以评估之前进行评估。扩展关键字的作者不得定义需要在此关键字之前评估的就地应用器。
此关键字的注释结果是此关键字子模式验证的实例属性名称集合。应用于同一实例位置的多个模式中的“unevaluatedProperties”关键字的注释结果通过获取集合的并集来合并。
省略此关键字与空模式具有相同的断言行为。
不支持注释收集的实现必须在遇到此关键字时引发错误。
“propertyNames”的值必须是有效的 JSON Schema。
如果实例是对象,则此关键字验证实例中的每个属性名称是否针对提供的模式进行验证。请注意,模式正在测试的属性名称始终是字符串。
省略此关键字与空模式具有相同的行为。
JSON Schema 被定义为平台无关。因此,为了提高跨平台的兼容性,实现应符合标准的验证输出格式。本节描述了消费者正确解释验证结果所需的最低要求。
JSON Schema 输出使用第 4.2.1 节中描述的 JSON Schema 数据实例模型定义。实现可以根据其特定语言和平台的支持情况偏离此模型,但是建议输出通过序列化或其他方式可转换为此处定义的 JSON 格式。
本规范定义了四种输出格式。有关每种格式的要求,请参阅“输出结构”部分。
实现应至少提供“标志”、“基本”或“详细”格式,可以提供“详细”格式。如果提供一个或多个复杂格式,它还必须提供“标志”格式。实现应在其文档中指定其支持的格式。
除了简单的“标志”输出之外,其他信息有助于调试模式或实例。每个子结果应至少包含本节中的信息。
包含所有这些组件的单个对象被认为是输出单元。
实现可以自由选择提供其他信息。
遵循验证路径的验证关键字的相对位置。该值必须用 JSON 指针表示,并且必须包含任何按引用应用器,例如“$ref”或“$recursiveRef”。
#/properties/width/$ref/minimum
请注意,由于包含这些按引用应用器关键字,此指针可能无法通过正常的 JSON 指针过程解析。
此信息的 JSON 键是“keywordLocation”。
验证关键字的绝对取消引用位置。该值必须用绝对 URI 表示,使用相关模式对象的规范 URI,并且不得包含按引用应用器(例如“$ref”或“$recursiveRef”)作为非终端路径组件。如果错误或注释是针对该关键字的,例如不可解析的引用,它可以以这些关键字结尾。
https://example.com/schemas/common#/$defs/count/minimum
只有当相对位置不包含任何引用或模式未声明其“$id”为绝对 URI 时,才可以省略此信息。
此信息的 JSON 键是“absoluteKeywordLocation”。
正在验证的实例中 JSON 值的位置。该值必须用 URI 片段编码的 JSON 指针表示。
此信息的 JSON 键是“instanceLocation”。
验证产生的错误或注释。
对于错误,此规范未定义消息的具体措辞。实现需要提供这一点。
对于注释,每个产生注释的关键字都指定其格式。默认情况下,它是关键字的值。
失败验证的 JSON 键是“error”;对于成功验证,它是“annotation”。
对于两种分层结构,此属性将保存嵌套错误和注释。
失败验证中嵌套结果的 JSON 键是“errors”;对于成功验证,它是“annotations”。请注意复数形式,因为具有嵌套结果的关键字也可以具有本地错误或注释。
输出必须是一个包含名为“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 } ]
此实例将无法通过验证并产生错误,但推断产生注释的通过模式的示例是微不足道的。
具体而言,它将产生的错误是
请注意,这些示例中所示的错误消息措辞不是本规范的要求。实现应为其受众定制错误消息,或提供允许其用户定制其自身消息的模板机制。
在最简单的情况下,只需要满足“valid”valid 属性的布尔结果。
{ "valid": false }
由于此格式不返回任何错误或注释,因此建议实现使用短路逻辑,以便在可以确定结果后立即返回失败或成功。例如,如果“anyOf”关键字包含五个子模式,而第二个子模式通过了,则无需检查其他三个子模式。该逻辑可以简单地返回成功。
“基本”结构是输出单元的扁平列表。
{ "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" } ] }
“详细”结构基于模式,对于人和机器来说都可能更具可读性。以这种方式组织结构使错误之间的关联更加明显。例如,缺少“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" } ] }
“详细”结构是一个完全实现的层次结构,与模式完全匹配。这种结构在需要错误位置的形式生成和验证中具有应用。
这种结构与“详细”结构的主要区别在于,所有结果都会被返回。这包括将被删除的子模式验证结果(例如,失败验证的注释,`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." } ] } ] }
为方便起见,JSON Schema 已提供用于验证实现生成的输出。其 URI 是:<https://json-schema.fullstack.org.cn/draft/2019-09/output/schema>.
JSON 已被 HTTP 服务器广泛用于自动化 API 和机器人。本节描述了如何在与支持媒体类型和 Web 链接 的协议一起使用时,以更 RESTful 的方式增强对 JSON 文档的处理。
建议由模式描述的实例使用“describedby”链接关系提供指向可下载 JSON 模式文件的链接,如链接数据协议 1.0,第 8.1 节中所定义。
在 HTTP 中,此类链接可以使用Link 标头附加到任何响应。此类标头的示例如下:
Link: <https://example.com/my-hyper-schema#>; rel="describedby"
媒体类型 MAY 允许使用“schema”媒体类型参数,这使得 HTTP 服务器能够根据模式执行内容类型协商。媒体类型参数 MUST 是一个以空格分隔的 URI 列表(即,相对引用无效)。
使用媒体类型 application/schema-instance+json 时,MUST 提供“schema”参数。
使用媒体类型 application/schema+json 时,MAY 提供“schema”参数。如果提供,它 SHOULD 包含与“$schema”关键字标识的相同 URI,并且 MAY 包含其他 URI。“$schema”URI MUST 被视为模式的规范元模式,而与作为媒体类型参数的备用或附加元模式的存在与否无关。
模式 URI 是不透明的,SHOULD NOT 自动取消引用。如果实现不理解提供的模式的语义,则实现可以改为跟随任何“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"
在通过网络用于超媒体系统时,HTTP 通常是用于分发模式的首选协议。如果行为不当的客户端比必要时更频繁地从网络上提取模式,而可以将模式缓存很长时间,那么它们可能会给服务器维护者带来问题。
HTTP 服务器 SHOULD 为 JSON 模式设置长时间缓存标头。HTTP 客户端 SHOULD 遵守缓存标头,并在其新鲜度期限内不重新请求文档。分布式系统 SHOULD 使用共享缓存和/或缓存代理。
User-Agent: product-name/5.4.1 so-cool-json-schema/1.0.2 curl/7.43.0
客户端 SHOULD 设置或预置特定于 JSON 模式实现或软件产品的 User-Agent 标头。由于符号按重要性降序排列,因此 JSON 模式库名称/版本应在更通用的 HTTP 库名称(如果有)之前。例如
客户端 SHOULD 能够使用“From”标头发出请求,以便服务器运营商可以联系潜在行为不当脚本的所有者。
模式和实例都是 JSON 值。因此,RFC 8259 中定义的所有安全注意事项都适用。
实例和模式通常由不受信任的第三方编写,并部署在公共互联网服务器上。验证器应注意,根据模式解析和验证不会消耗过多的系统资源。验证器 MUST NOT 陷入无限循环。
服务器 MUST 确保恶意方无法通过上传具有预先存在或非常相似的“$id”的模式来更改现有模式的功能。
单个 JSON 模式词汇表也可能具有自己的安全注意事项。请参阅相关规范以获取更多信息。
模式作者应注意“$comment”内容,因为恶意实现可能会违反规范将其显示给最终用户,或者如果预期这种行为则无法将其删除。
恶意模式作者可以在“$comment”中放置可执行代码或其他危险材料。实现 MUST NOT 解析或根据“$comment”内容采取其他行动。
JSON 模式的提议 MIME 媒体类型定义如下:
需要 JSON 模式特定媒体类型的 JSON 模式实例的提议 MIME 媒体类型定义如下:
[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 月。 |
[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 月。 |
考虑以下模式,它显示“$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 识别。
已创建各种工具来根据引用 (“$ref”) 的出现方式和位置重新排列模式文档。本附录讨论了哪些用例和操作符合本规范。
一组旨在一起使用的模式资源可以组织为每个资源都在自己的模式文档中,所有资源都在同一个模式文档中,或者介于两者之间的任何文档分组粒度。
存在许多工具可以执行各种引用删除。一个常见的例子是生成一个文件,其中所有引用都可以在该文件中解析。这通常用于简化分发,或简化编码,以便 JSON 模式库的各种调用不必跟踪和加载大量资源。
只要所有静态引用(例如,“$ref”)都使用解析为规范 URI 的 URI 引用,并且所有模式资源的根模式中都具有绝对 URI 作为“$id”,就可以安全且可逆地完成此转换。
满足这些条件后,每个外部资源都可以复制到“$defs”下,而不会破坏资源模式对象之间的任何引用,也不会改变验证或注释结果的任何方面。假设“$defs”下的模式名称都是唯一的,因为它们不会出现在嵌入资源的规范 URI 中,所以它们不会影响行为。
尝试删除所有引用并生成单个模式文档,并非在所有情况下都能生成与原始形式具有相同行为的模式。
由于“$ref”现在被视为与其他关键字一样,在同一个模式对象中允许使用其他关键字,因此在所有情况下完全支持非递归“$ref”删除可能需要相对复杂的模式操作。确定或提供一组安全的“$ref”删除转换超出了本规范的范围,因为它们不仅取决于模式结构,还取决于预期用途。
考虑以下两个模式,它们描述了一个简单的递归树结构,其中树中的每个节点都可以有一个任何类型的“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”模式的根模式,因此我们使用其“https://example.com/strict-tree”的基准 URI,这将为“$recursiveRef”生成最终解析的 URI“https://example.com/strict-tree#”。
通过这种方式,“tree”模式中的递归将递归到“strict-tree”的根,而不是只将“strict-tree”应用于实例根,而是将“tree”应用于实例子节点。
如果词汇表旨在广泛使用,并且可能与其他词汇表结合使用,词汇表作者应注意避免关键字名称冲突。JSON Schema 没有提供任何正式的命名空间系统,但也没有约束关键字名称,允许使用任意数量的命名空间方法。
词汇表可以相互构建,例如通过定义其关键字相对于另一个词汇表中的关键字的行为,或者通过使用另一个词汇表中的关键字,但具有受限或扩展的一组可接受的值。并非所有这种词汇表重用都会导致一个与构建它的词汇表兼容的新词汇表。词汇表作者应明确记录预期兼容性的级别(如果有的话)。
元模式作者不应使用“$vocabulary”来组合多个词汇表,这些词汇表为同一个关键字定义了冲突的语法或语义。由于语义冲突通常无法通过模式验证检测到,因此预计实现不会检测到此类冲突。如果声明了冲突的词汇表,则结果行为未定义。
词汇表作者应提供一个元模式,该元模式验证词汇表关键字在它们自身上的预期用法。此类元模式不应禁止其他关键字,并且不应禁止核心词汇表中的任何关键字。
建议元模式作者使用 "allOf" 关键字引用每个词汇表的元模式,尽管对于某些用例,构建元模式的其他机制可能更合适。
元模式的递归性质使“$recursiveAnchor”和“$recursiveRef”关键字对于扩展现有元模式特别有用,正如在扩展验证元模式的 JSON 超级模式元模式中所见。
元模式可以施加额外的约束,包括描述除了与声明的词汇表关联的元模式所描述的之外,在任何词汇表中都不存在的关键字。这允许将使用限制在词汇表的一个子集中,以及验证本地定义的关键字,这些关键字不打算重复使用。
但是,元模式不应与它们声明的任何词汇表相矛盾,例如通过要求与词汇表期望的不同的 JSON 类型。结果行为未定义。
旨在本地使用,无需在任意实现中测试词汇表支持的元模式可以安全地完全省略“$vocabulary”。
此元模式明确声明了核心词汇表和应用器词汇表,以及扩展词汇表,并使用“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”函数纯粹用作注释,也可以对其进行验证,如 验证规范 中所述)。
虽然预期引用的存在对验证结果是透明的,但代码生成器和 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”属性没有。它只是一个带有子字段的字段,而不是一个独立类的实例。
这种使用风格要求注释与引用位于同一个对象中,该引用必须被识别为引用。
感谢 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 对文档的提交和补丁。