简体   繁体   English

JSON 带有可选项目的模式数组元组验证

[英]JSON Schema array tuple validation with optional items

I'm writing a JSON schema capable of validating an array where each item has a different schema and the ordinal index of each item is meaningful but some items are optional.我正在编写一个 JSON 模式,该模式能够验证一个数组,其中每个项目都有不同的模式,每个项目的序号索引是有意义的,但有些项目是可选的。

However, using the current spec (2020-12) I can't use prefixItems with optional items.但是,使用当前规范 (2020-12) 我不能将prefixItems与可选项目一起使用。 To be clear:要清楚:

  • all required items should exist and should be validated against index matching schema所有必需的项目都应该存在并且应该根据索引匹配模式进行验证
  • missing optional items shouldn't invalidate the result缺少可选项目不应使结果无效
  • existing optional items should be validated against the index matching schema现有的可选项目应根据索引匹配模式进行验证

Here is an example of the data I'm trying to validate:这是我要验证的数据示例:

(without optional array elements) (没有可选的数组元素)

[
    {
        "name": "Document 1 required",
        "url": "random.random/12313213.pdf"
    },
    {
        "name": "Document 2 required",
        "url": "random.random/12313213.pdf"
    }
]

(with optional array elements) (带有可选的数组元素)

[
    {
        "name": "Document 1 required",
        "url": "random.random/1231322313.pdf"
    },
    {
        "name": "Optional document 1",
        "url": "random.random/1231356213.pdf"
    },
    {
        "name": "Document 2 required",
        "url": "random.random/1231893213.pdf"
    },
    {
        "name": "Optional document 2",
        "url": "random.random/1231336213.pdf"
    }
]

Here is the current schema I'm using:这是我正在使用的当前架构:

{
    "type": "array",
    "items": false,
    "prefixItems": [
        {
            "type": "object",
            "properties": {
                "name": {
                    "type": "string",
                    "const": "Document 1 required"
                },
                "url": {
                    "type": "string",
                    "format": "uri"
                }
            }
        },
        {
            "type": "object",
            "properties": {
                "name": {
                    "type": "string",
                    "const": "Document 2 required"
                },
                "url": {
                    "type": "string",
                    "format": "uri"
                }
            }
        }
    ]
}

I've tried adding a oneOf in the optional items position with the correct schema and a stub {} but it doesn't seem to work as:我尝试使用正确的架构和存根{}在可选项目 position 中添加oneOf但它似乎不起作用:

{
    "type": "array",
    "items": false,
    "prefixItems": [
        {
            "type": "object",
            "properties": {
                "name": {
                    "type": "string",
                    "const": "Document 1 required"
                },
                "url": {
                    "type": "string",
                    "format": "uri"
                }
            }
        },
        {
            "oneOf": [
                {
                    "type": "object",
                    "properties": {
                        "name": {
                            "type": "string",
                            "const": "Optional document 1"
                        },
                        "url": {
                            "type": "string",
                            "format": "uri"
                        }
                    }
                },
                {}
            ]
        },
        {
            "type": "object",
            "properties": {
                "name": {
                    "type": "string",
                    "const": "Document 2 required"
                },
                "url": {
                    "type": "string",
                    "format": "uri"
                }
            }
        },
        {
            "oneOf": [
                {
                    "type": "object",
                    "properties": {
                        "name": {
                            "type": "string",
                            "const": "Optional document 2"
                        },
                        "url": {
                            "type": "string",
                            "format": "uri"
                        }
                    }
                },
                {}
            ]
        }
    ]
}

Also tried different approaches using contains and additionalItems .还尝试了使用containsadditionalItems的不同方法。 However they either don't work for multiple schemas or don't guarantee the order for the optional items.但是,它们要么不适用于多个模式,要么不保证可选项目的顺序。

Note: the example uses similar schemas that could be simplified but it is used to showcase the issue in question.注意:该示例使用可以简化的类似模式,但它用于展示有问题的问题。

Your schema isn't working out because the schema {} is always true -- therefore when you say "oneOf": [ {.. some schema.. }, {} ] you are essentially negating the first schema - because the second schema must always be true, the first schema must be false.您的架构无法正常工作,因为架构{}始终为真 - 因此当您说"oneOf": [ {.. some schema.. }, {} ]您实际上是在否定第一个架构 - 因为第二个架构必须始终为真,第一个模式必须为假。 Which is the opposite of what you want!这与你想要的相反!

I think you're expecting prefixItems to be more complicated than it actually is.我认为您期望prefixItems比实际更复杂。 Each schema in the prefixItems list is already optional, in the sense that if the corresponding item is not there in the data instance, there is no failure. prefixItems列表中的每个模式都已经是可选的,从某种意义上说,如果数据实例中不存在相应的项目,则不会失败。

For example, consider validating this data [1] against this schema:例如,考虑针对此架构验证此数据[1]

{
  "prefixItems": [
    { "type": "integer" },
    false
  ]
}

The overall result of this evaluation is true -- the first data element validates against "type": integer , and the second schema, false , never runs because there is no item to run against.此评估的总体结果是true的——第一个数据元素根据"type": integer ,第二个模式false永远不会运行,因为没有要运行的项目。 If we passed a data instance of [ 1, 1 ] then validation would fail.如果我们传递了[ 1, 1 ]的数据实例,那么验证将失败。

If you want to ensure that all of the data items corresponding to prefixItems subschemas are actually present, then you would need to use minItems : eg for the above example you would add "minItems": 2 .如果要确保与prefixItems子模式对应的所有数据项实际存在,则需要使用minItems :例如,对于上面的示例,您将添加"minItems": 2

One major caveat is that you need to put all of your required items first.一个主要的警告是,您需要首先放置所有必需的项目。 You cannot interleave optional items in between required items, as the schemas in prefixItems are always applied in order, and if one of the schemas doesn't evaluate to true, there is no "skipping" of items to the next one.您不能在必需项之间交错可选项,因为prefixItems中的架构总是按顺序应用,如果其中一个架构未评估为真,则不会“跳过”项目到下一个。 The first prefixItems schema always applies to the first data instance, the second prefixItems schema always applies to the second data instance, and so on.第一个 prefixItems 架构始终适用于第一个数据实例,第二个 prefixItems 架构始终适用于第二个数据实例,依此类推。

On the other hand, if you can get away with not specifying order at all, you can use multiple contains directives (note that minContains defaults to 1 when not explicitly provided):另一方面,如果您可以完全不指定 order,则可以使用多个contains指令(注意minContains在未明确提供时默认为 1):

"allOf": [
  { "contains": { schema for one of the required items, that can be anywhere... },
  { "contains": { schema for another required item... },
  { "minContains": 0, "contains": { schema for an optional item... },
  ...
]

You could also put your optional items into additionalItems with anyOf :您还可以使用anyOf将可选项目放入additionalItems中:

"additionalItems": {
  "anyOf": [
    { ..schema of an optional item.. },
    { "" },
    ...
  ]
}

If you can move all of your mandatory non-optional items to the front of the array, you can use prefixItems to define the required items, in order, followed by additionalItems to define a single schema for all other (optional) items, assuming the additional options are uniform.如果您可以将所有必需的非可选项目移动到数组的前面,则可以使用prefixItems来定义必需的项目,然后使用 AdditionalItems 来为所有additionalItems (可选)项目定义一个模式,假设其他选项是统一的。

Use minItems to make sure the number of required items are present.使用minItems确保存在所需项目的数量。 You can use maxItems to limit the total number of items in the array, effectivly allowing you to limit the number of optional items, if you need to do so.您可以使用maxItems来限制数组中的项目总数,如果需要,您可以有效地限制可选项目的数量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM