JSON-schema 错误的成功验证

Erroneous successful validation by JSON-schema

节点中的字段取决于实体的值。也就是说,如果 entity = "pd",那么节点有一些字段,而 entity = "top" - 节点有完全不同的字段,尽管它们是严格要求的。出于某种原因,JSON 字符串被有效模式接受,即使没有按要求在节点中定义字段。我已经整个脑袋都碎了,最多的方案哪里会出错? JSON-架构:

{
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "object",
  "title": "The Root Schema",
  "required": [
    "virtual"
  ],
  "properties": {
    "virtual": {
      "$id": "#/properties/virtual",
      "type": "array",
      "title": "The Virtual Schema",
      "items": {
        "$id": "#/properties/virtual/items",
        "type": "object",
        "title": "The Items Schema",
        "required": [
          "type",
          "path",
          "entity",
          "nodes"
        ],
        "properties": {
          "type": {
            "$id": "#/properties/virtual/items/properties/type",
            "type": "string",
            "title": "The Type Schema",
            "default": "",
            "examples": [
              "bus"
            ],
            "pattern": "^(.*)$"
          },
          "path": {
            "$id": "#/properties/virtual/items/properties/path",
            "type": "string",
            "title": "The Path Schema",
            "default": "",
            "examples": [
              "VBUS2"
            ],
            "pattern": "^(.*)$"
          },
          "entity": {
            "$id": "#/properties/virtual/items/properties/entity",
            "type": "string",
            "title": "The Entity Schema",
            "default": "",
            "examples": [
              "topaz"
            ],
            "enum": ["pde", "topaz"],
            "pattern": "^(.*)$"
          },
          "nodes": {
            "$id": "#/properties/virtual/items/properties/nodes",
            "type": "array",
            "title": "The Nodes Schema",
            "items": {
                "$id": "#/properties/virtual/items/properties/nodes/items",
                "type": "object",
                "title": "The Items Schema"
            }
          }
        }
      }
    }
  },
  "anyOf": [
    {       
        "if": {
            "properties": { "virtual": { "properties": { "entity": { "const": "topaz" } } } } 
        },
        "then": {
            "properties": { 
                "virtual": { 
                    "properties": { 
                        "nodes": {  
                            "items": {
                                "required": [
                                    "uid",
                                    "utype",
                                    "uaddress",
                                    "unozzles"
                                ],
                                "properties": {
                                    "uid": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/uid",
                                        "type": "integer",
                                        "title": "The Uid Schema",
                                        "default": 0,
                                        "examples": [
                                            1
                                        ]
                                    },
                                    "utype": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/utype",
                                        "type": "string",
                                        "title": "The Utype Schema",
                                        "default": "",
                                        "examples": [
                                            "dispenser"
                                        ],
                                        "pattern": "^(.*)$" 
                                    },
                                    "uaddress": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/uaddress",
                                        "type": "string",
                                        "title": "The Uaddress Schema",
                                        "default": "",
                                        "examples": [
                                            "false"
                                        ],
                                        "pattern": "^(.*)$"
                                    },
                                    "unozzles": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/unozzles",
                                        "type": "boolean",
                                        "title": "The Unozzles Schema",
                                        "default": false,
                                        "examples": [
                                            false
                                        ]
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        "if": { 
            "properties": { "virtual": { "properties": { "entity": { "const" : "pde" } } } }
        },
        "then": {
            "properties": {
                "virtual": {
                    "properties": {
                        "nodes": {
                            "items": {
                                "required": [                                   
                                    "id",
                                    "type",
                                    "address",
                                    "nozzles"
                                ],
                                "properties": {
                                    "id": {                     
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/id",
                                            "type": "string",
                                            "title": "The Id Schema",
                                            "default": "",
                                            "examples": [
                                                "vrt_1"
                                            ],
                                        "pattern": "^(.*)$"
                                    },
                                    "type": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/type",
                                        "type": "string",
                                        "title": "The Type Schema",
                                        "default": "",
                                        "examples": [
                                            "dispenser"
                                        ],
                                        "pattern": "^(.*)$"
                                    },
                                    "address": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/address",
                                        "type": "integer",
                                        "title": "The Address Schema",
                                        "default": 0,
                                        "examples": [
                                            1
                                        ]
                                    },
                                    "nozzles": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/nozzles",
                                        "type": "array",
                                        "title": "The Nozzles Schema",
                                        "items": {
                                            "$id": "#/properties/virtual/items/properties/nodes/items/properties/nozzles/items",
                                            "type": "integer",
                                            "title": "The Items Schema",
                                            "default": 0,
                                            "examples": [
                                                1,
                                                2,
                                                3
                                            ]
                                        }
                                    }
                                }
                            }                                           
                        }
                    }
                }
            }
        }
    }
  ]  
}

这个JSON有效:

{
    "virtual": [
        {
            "type": "bus",
            "path": "VUS1",
            "entity": "pde",
            "nodes": [
                {
                    "id": "vrt_1",
                    "type": "string",
                    "address": 1,
                    "nozzles": [1, 2, 3]
                },
                {
                    "id": "vrt_2",
                    "type": "string",
                    "address": 2,
                    "nozzles": [1, 2, 3]
                }
            ]
        },
        {
            "type": "bus",
            "path": "VUS2",
            "entity": "topaz",
            "nodes": [          
                {
                    "uid": 1,
                    "utype": "string",
                    "uaddress": "false",
                    "unozzles": false
                },
                {
                    "uid": "vrt_1",
                    "utype": "string",
                    "uaddress": "false",
                    "unozzles": false
                }
            ]
        }
    ]
}

并且这个 JSON 不应该应用,但被认为是有效的:

{
    "virtual": [
        {
            "type": "bus",
            "path": "VUS1",
            "entity": "pde",
            "nodes": [
                {
                    "id_not_valid": "failure",
                    "type": 1,
                    "address": false,
                    "nozzles": [1, 2, 3]
                },
                {
                    "id": "vrt_2",
                    "type": "string",
                    "address": false,
                    "nozzles": [1, 2, 3]
                }
            ]
        },
        {
            "type": "bus",
            "path": "VUS2",
            "entity": "topaz",
            "nodes": [          
                {
                    "uid_not_valid": "failure",
                    "utype": 1,
                    "uaddress": "false",
                    "unozzles": false
                }
            ]
        }
    ]
}

理论上,第二个JSON不应该被验证。有几个原因:

  1. 对于实体= "pd",必填字段为"id"、"type"、“地址"and"喷嘴”。在 JSON 的第二行中,字段 "id" 被字段 "id_not_valid" 替换 - > 必填字段“ id ”不存在,验证必须以失败告终。 entity="top" - "the uid" 被替换为 "id_not_valid"
  2. 对于entity="pd",address字段是token类型,在第2JSON行设置为false,对应"boolean"类型,但是校验仍然发生(如果您将数组或字符串值分配给地址,则相同)。对于entity="top"类型,类型是string,但是赋给它的整数值1也被验证器假定为正确的string。

但是下面链接上的在线验证器说一切正常,JSON 都符合方案。

The first site

Second site

The third website

所以我认为这个方案有错误。
该方案本身就是由这个例子制定的 Example of JSON schema compilation

任何关于修复 JSON-schema 的评论和提示,请

架构 格式错误。

(我忽略了一个事实,即模式声明 entity 应该是 "pde""topaz",但实例有 "pd""top" .我认为这是一个错字。)

anyOf 中,您有两个项目,每个项目都有一个 if 条件关键字。该关键字呈现的架构是

{
  "properties": {
    "virtual": {
      "properties": {
        "entity": {
          "const": "topaz"
        }
      }
    }
  }
}

这是说如果virtual有一个entity属性,那么应该是"topaz"。但是 properties 的工作方式是,如果实例是一个对象 ,它只会失败验证 。但是在 #/properties 中,您声明 virtual 应该是一个对象数组,其中 每个项目 包含一个 entity 属性。

由于 virtual 在您的实例中是一个数组,因此 anyOf 传递中 if 条件关键字的 none,因此它们遵循 else 那些不存在的子模式的关键字(因此默认情况下通过)。这导致 anyOf 通过的两个子模式。

认为 您要做的是根据 entity 属性 的值验证数组中的每个项目那个项目。这意味着您可以在数组中同时拥有 pde 项和 topaz 项。

为此,您需要隔离方差所在的位置。在您的例子中,它是 virtual 数组中的项目级别。这是您需要放置 anyOf.

的地方

因此您需要将 anyOf 添加到 #/properties/virtual/items。这是架构中 if/then 构造可以关闭 entity 属性 并强制执行 nodes 属性 的唯一一点.


编辑 我要更改的内容

  1. 删除所有内部 $id 声明。它们只是重申了文档中的位置,并没有提供额外的功能。
  2. entity 中删除 typepattern 声明。 enum 在这里就足够了,因为它声明值必须是数组中的一项。由于这些都是字符串并且匹配给定的模式,因此这些关键字是多余的。
  3. anyOf 移动到 virtual 内的 properties 关键字旁边,并将其更改为 oneOf。这是您可以访问 entities 属性 和 nodes 属性 的最具体的位置。将其更改为 oneOf 可确保恰好有一个为真。
  4. 删除 if/then 结构,只在 then 部分包含常量值。

最后,它的结构如下:

{
  ... ,
  "properties": {
    "virtual": {
      "type": "array",
      "title": "The Virtual Schema",
      "items": {
        "type": "object",
        "title": "The Items Schema",
        "required": [ "type", "path", "entity", "nodes" ],
        "properties": {
          "type": { ... },
          "path": { ... },
          "entity": {
            "title": "The Entity Schema",
            "default": "",
            "examples": [
              "topaz"
            ],
            "enum": ["pde", "topaz"]
          }
        },
        "oneOf": [
            {
                "properties": {
                    "entity": {"const": "topaz"},
                    "nodes": { ... }
                }
            },
            {
                "properties": {
                    "entity": {"const": "pde"},
                    "nodes": { ... }
                }
            }
        ]
      }
    }
  } 
}

在这里,我们声明 virtual 数组中的项目必须是需要 4 个属性的对象:typepathentitynodes。我们使用 properties 关键字显式定义 typepathentity。但是我们有条件地使用 oneOf 定义 nodes 属性 并在每种情况下为 entity 属性 指定一个常数值。