JSON模式数组验证使用oneOf失败



希望我能在这个验证问题上找到一些帮助:我有一个JSON数组,它可以有多种对象类型(视频、图像)。在该数组中,对象具有一个rel字段值。我正在处理的情况是,只能有一个对象允许"rel": "primaryMedia"——视频或图像。

以下是图像和视频情况的对象表示,两者都显示了"rel": "primaryMedia"

{
"media": [
{
"caption": "Caption goes here",
"id": "ncim87659842",
"rel": "primaryMedia",
"type": "image"
},
{
"description": "Shaima Swileh arrived in San Francisco after fighting for 17 months to get a waiver from the U.S. government to be allowed into the country to visit her son.",
"headline": "Yemeni mother arrives in U.S. to be with dying 2-year-old son",
"id": "mmvo1402810947621",
"rel": "primaryMedia",
"type": "video"
}
]
}

以下是我创建的模式的精简版本,用于使用oneOf对此进行验证(假设这将处理我的情况)。然而,它并没有按预期工作。

{
"$id": "http://example.com/schema/rockcms/article.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {},
"properties": {
"media": {
"items": {
"oneOf": [
{
"additionalProperties": false,
"properties": {
"caption": {
"type": "string"
},
"id": {
"type": "string"
},
"rel": {
"enum": [
"primaryMedia"
],
"type": "string"
},
"type": {
"enum": [
"image"
],
"type": "string"
}
},
"required": [
"caption",
"id",
"rel",
"type"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"description": {
"type": "string"
},
"headline": {
"type": "string"
},
"id": {
"type": "string"
},
"rel": {
"enum": [
"primaryMedia"
],
"type": "string"
},
"type": {
"enum": [
"video"
],
"type": "string"
}
},
"required": [
"description",
"headline",
"id",
"rel",
"type"
],
"type": "object"
}
]
},
"type": "array"
}
}
}

在上使用JSON模式验证器https://www.jsonschemavalidator.net,模式在数据正确呈现时进行验证,但在试图捕捉错误时不起作用。

在下面的情况中,为视频添加了headline,但缺少id。这应该会失败,因为视频中不允许使用headline,并且需要id

{ 
"media": [
{
"headline": "Yemeni mother arrives in U.S. to be with dying 2-year-old son",
"rel": "primaryMedia",
"type": "video"
}
]
}

然而,我从验证器得到的结果并不完全是意料之中的。似乎它在响应中混淆了两个对象模式。

除此之外,我还发现该模式将允许在media中填充视频和图像对象,这是不期望的。

我一直想弄清楚我做错了什么,但被难住了。如果有人愿意提供反馈,我将不胜感激。提前感谢!


验证器响应:

消息:JSON对"oneOf"中的任何架构都无效。架构路径:#/properties/media/items/oneOf

消息:尚未定义属性"headline",架构不允许其他属性。架构路径:#/properties/media/items/oneOf/0/additionalProperties

消息:枚举中未定义值"video"。架构路径:#/properties/media/items/oneOf/0/properties/type/enum

消息:对象缺少必需的属性:description,id。架构路径:#/properties/media/items/oneOf/1/必需

消息:对象缺少必需的属性:caption,id。架构路径:#/properties/media/items/oneOf/0/必需

您的问题由三部分组成,但前两部分是链接的,所以我将解决这些问题,尽管它们没有"解决方案";像这样的

  1. 如何验证数组中只有一个对象具有特定键,而其他对象没有

您无法使用JSON架构执行此操作。适用于数组的JSON模式关键字集不具有表示";其中一个值必须匹配模式";,而是适用于数组中的所有项目或数组中的特定项目(如果items是与对象相对的数组)。https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.4

  1. 验证输出不是我所期望的。我希望只看到oneOf的失败分支,它与我的对象类型有关由CCD_ 12密钥定义

JSON模式规范(截至draft-7)没有指定任何返回错误的格式,但是您得到的错误结构非常"漂亮";完整的";就它告诉您的内容而言(类似于我们为draft-8指定应返回的错误)。

考虑一下,验证器对您的模式或JSON实例的业务逻辑一无所知。在验证JSON实例时,验证器可以遍历所有值,并针对所有适用的子模式测试验证规则。看看您的错误,oneOf中的两个模式都适用于数组中的所有项,因此所有项都经过了验证测试。如果其中一个不满足条件,其他人也将接受测试。在使用oneOf时,验证器无法知道您的意图是什么。

您可以通过使用if/then组合来解决此问题。如果您的if模式只是类型的常量,而then模式是完整的对象类型,那么您可能会得到更干净的错误响应,但我还没有测试过这个理论。

  1. 我希望数组中的所有项都是其中一种类型。这是怎么回事

根据规范…

items:

如果"项目";是一个架构,如果数组根据该架构成功验证。

oneOf:

如果实例
仅针对该
关键字的值定义的一个架构成功验证,则实例将针对该关键字成功验证。

您所做的是:数组中的每个项都应该根据[schemaA]有效。SchemA:根据以下模式之一,对象应该是有效的:[oneOf]中的模式。

当你认为";项目必须是以下";,但是CCD_ 22独立地将值模式应用于数组中的每个项。

要实现您的意思,请将oneOf移到items之上,然后将其中一个媒体类型重构为另一个项模式。

这是一个sudo模式。

oneOf: [items: properties: type: const: image], [items: properties: type: image]

如果有任何不清楚的地方,或者你有任何后续问题,请告诉我。