提问者:小点点

使用其中一个进行JSON模式数组验证


希望我能在这个验证问题上找到一些帮助:我有一个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"
    }
  ]
}

下面是我创建的模式的精简版本,我使用的之一验证了这一点(假设这可以处理我的情况)。然而,它并没有像预期的那样工作。

{
  "$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"
    }
  ]
}

然而,我从验证器得到的结果并不是完全预期的。它的响应似乎将两个对象模式混为一谈。

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

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


验证程序响应:

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

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

消息:枚举中没有定义值“视频”。模式路径:#/属性/媒体/项/oneOf/0/属性/类型/枚举

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

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


共1个答案

匿名用户

你的问题由三部分组成,但前两部分是联系在一起的,所以我将解决这些问题,尽管它们本身没有“解决方案”。

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

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

JSON模式规范(从草案7开始)没有为返回错误指定任何格式,但是您得到的错误结构在它告诉您的方面是相当“完整”的(类似于我们为草案8指定应该返回错误的方式)。

考虑一下,验证器在业务逻辑方面对您的架构或JSON实例一无所知。验证JSON实例时,验证器可能会逐步检查所有值,并根据所有适用的子模式测试验证规则。查看您的错误,oneOf中的两个模式都适用于数组中的所有项,因此所有项都要进行验证测试。如果一个不满足条件,其他的也将进行测试。当使用中的一个时,验证器无法知道您的意图是什么。

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

从规范。。。

项目

如果“items”是一个模式,那么如果数组中的所有元素都成功地根据该模式进行验证,则验证将成功。

one Of

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

你所做的是说:数组中的每一项都应该根据[schemaA]有效。模式:对象应该是有效的,根据这些模式:[oneOf内的模式]。

当您认为项目必须是以下项目之一时,我可以看出这是多么令人困惑,但是项目独立地将值模式应用于数组中的每个项目。

要使其符合您的意思,请将项中的项移到项上方,然后将其中一种媒体类型重构为另一种媒体项架构。

这里有一个sudo模式。

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

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