具有多个嵌套的AnyOf

时间:2019-11-11 06:08:47

标签: json jsonschema

根据上一个答案,我建立了一个满足我要求的方案。该问题及其答案可见here

结果方案:

{   
    "definitions": {},
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": [
        "virtual"
    ],
    "properties": {
        "virtual": {
            "type": "array",
            "items": {
                "type": "object",
                "required": [
                    "type",
                    "path",
                    "entity",
                    "nodes"
                ],
                "properties": {
                    "type": {
                        "type": "string"
                    },
                    "path": {
                        "type": "string"
                    },
                    "entity": {
                        "enum": ["pde", "topaz"]
                    }         
                },
                "anyOf": [
                    {
                        "properties": {
                            "entity": {"const": "pde"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "title": "The Items Schema",
                                    "required": [
                                        "id",
                                        "type",
                                        "address",
                                        "nozzles"
                                    ],
                                    "properties": {
                                        "id": {
                                            "type": "string"
                                        },
                                        "type": {
                                            "type": "string"
                                        },
                                        "address": {
                                            "type": "integer"
                                        },
                                        "nozzles": {
                                            "type": "array",
                                            "items": {
                                                "type": "integer"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    {
                        "properties": {
                            "entity": {"const": "topaz"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "uid",
                                        "utype",
                                        "uaddress",
                                        "unozzles"
                                    ],
                                    "properties": {
                                        "uid": {
                                            "type": "integer"
                                        },
                                        "utype": {                  
                                            "type": "string"
                                        },
                                        "uaddress": {
                                            "type": "string"
                                        },
                                        "unozzles": {
                                            "type": "boolean"
                                        }
                                    }
                                }
                            }
                        } 
                    }
                ]
            }
        }
    }
}

和JSON:

{
    "virtual": [
        {
            "type": "bus",
            "path": "VBUS1",
            "entity": "pde",
            "nodes": [
                {
                    "id": "vrt_1",
                    "type": "dispenser",
                    "address": 1,
                    "nozzles": [1, 2, 3]
                },
                {
                    "id": "vrt_2",
                    "type": "dispenser",
                    "address": 2,
                    "nozzles": [4, 5, 3]
                }
            ]
        },
        {
            "type": "bus",
            "path": "VBUS2",
            "entity": "topaz",
            "nodes": [          
                {
                    "uid": 1,
                    "utype": "dispenser",
                    "uaddress": "false",
                    "unozzles": true
                },
                {
                    "uid": 2,
                    "utype": "dispenser",
                    "uaddress": "true",
                    "unozzles": false
                }
            ]
        }
    ]
}

出现以下问题。当type = bus时,JSON具有路径和实体字段。但是,如果type = io,则缺少路径和实体字段,而节点字段看起来与上述两个字段不同。

因此,我需要具有可以跟踪类型字段值的anyOf和适用于type = bus的另一个anyOf。

我将尝试更清楚地解释。有必要跟踪类型字段的值,如果它等于bus,则出现路径和实体字段。根据实体的值,节点字段具有特定的结构(正是上图中所写的结构)。

我试图创建一个嵌套有anyOf的架构:

{
    "definitions": {},
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": [
        "virtual"
    ],
    "properties": {
        "virtual": {
            "type": "array",
            "items": {
                "type": "object",
                "required": [
                    "type"
                ],
                "properties": {
                    "type": {
                        "enum": ["bus", "io"]
                    }
                },
                "anyOf": [
                    {

                        "properties": {
                            "type": {"const": "bus"},
                            "path": { "type": "string" },
                            "entity": { "enum": ["topaz", "pde"] }
                        },
                        "anyOf":[
                        {
                            "properties":{
                                "entity": {"const": "pde"},
                                "nodes": {
                                    "type": "array",
                                    "items": {
                                        "type": "object",
                                        "required": [
                                            "id",
                                            "type",
                                            "address",
                                            "nozzles"
                                        ],
                                        "properties": {
                                            "id": { "type": "string" },
                                            "type": { "type": "string" },
                                            "address": { "type": "integer" },
                                            "nozzles": {
                                                "type": "array",
                                                "items": { "type": "integer" }
                                            }
                                        }
                                    }
                                }
                            }
                        },
                        {
                            "entity": {"const": "topaz"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "uid",
                                        "utype",
                                        "uaddress",
                                        "unozzles"
                                    ],
                                    "properties": {
                                        "uid": { "type": "integer" },
                                        "utype": { "type": "string" },
                                        "uaddress": { "type": "string" },
                                        "unozzles": { "type": "boolean" }
                                    }
                                }
                            }
                        }
                        ]
                    },
                    {
                        "properties": {
                            "type": {"const": "io"},
                            "nodes": {
                                "type": "array",
                                "items":{
                                    "type": "object",
                                    "required": [
                                        "num",
                                        "key",
                                        "title",
                                        "path"
                                    ],
                                    "properties": {
                                        "num": { "type": "integer" },
                                        "key": { "type": "integer" },
                                        "title": { "type": "string" },
                                        "path": { "type": "string" }
                                    }
                                }
                            }
                        }
                    }
                ]
            }
        }   
    }
} 

Example of checking the scheme on the site

但是,正如预期的那样,该方案甚至接受了那些不应该接受的方案。

无效模式的示例。没有用于类型=总线,实体= pde的必填ID字段。没有用于类型=总线,实体=黄玉的必填uid字段。感觉像第二个嵌套的anyOf被忽略了。

{
  "virtual": [
    {
      "type": "bus",
      "path": "VBUS1",
      "entity": "pde",
      "nodes": [
        {
          "not_id": "vrt_1",
          "type": "dispenser",
          "address": 1,
          "nozzles": [
            1,
            2,
            3
          ]
        },
        {
          "id": "vrt_2",
          "type": "dispenser",
          "address": 2,
          "nozzles": [
            4,
            5,
            3
          ]
        }
      ]
    },
    {
      "type": "bus",
      "path": "VBUS2",
      "entity": "topaz",
      "nodes": [
        {
          "not_uid": 1,
          "utype": "dispenser",
          "uaddress": "false",
          "unozzles": true
        },
        {
          "uid": 2,
          "utype": "dispenser",
          "uaddress": "true",
          "unozzles": false
        }
      ]
    },
    {
      "type": "io",
      "nodes": [
        {
          "num": 1,
          "key": 123,
          "title": "123",
          "path": "123"
        }
      ]
    }
  ]
}

Check the validity of the incorrect JSON

在这种情况下,type字段的anyOf可以正常工作。我认为这个问题是由于该方案的布局错误而再次出现的,但是我在嵌套的anyOf上找不到Internet上的信息。

当试图将所有支票插入到anyOf中时,一切都会按预期工作。

{   
    "definitions": {},
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": [
        "virtual"
    ],
    "properties": {
        "virtual": {
            "type": "array",
            "items": {
                "type": "object",
                "required": [
                    "type"
                ],
                "properties": {
                    "type": { "enum": ["bus", "io"] }        
                },
                "anyOf": [
                    {
                        "properties": {
                            "type": {"const": "bus"},
                            "path": { "type": "string" },
                            "entity": {"const": "pde"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "title": "The Items Schema",
                                    "required": [
                                        "id",
                                        "type",
                                        "address",
                                        "nozzles"
                                    ],
                                    "properties": {
                                        "id": { "type": "string" },
                                        "type": { "type": "string" },
                                        "address": { "type": "integer" },
                                        "nozzles": {
                                            "type": "array",
                                            "items": { "type": "integer" }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    {
                        "properties": {
                            "type": {"const": "bus"},
                            "path": { "type": "string" },
                            "entity": {"const": "topaz"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "uid",
                                        "utype",
                                        "uaddress",
                                        "unozzles"
                                    ],
                                    "properties": {
                                        "uid": { "type": "integer" },
                                        "utype": { "type": "string" },
                                        "uaddress": { "type": "string" },
                                        "unozzles": { "type": "boolean" }
                                    }
                                }
                            }
                        } 
                    },
                    {
                        "properties": {
                            "type": {"const": "io"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "num",
                                        "key",
                                        "title",
                                        "path"
                                    ],
                                    "properties": {
                                        "num": { "type": "integer" },
                                        "key": { "type": "integer" },
                                        "title": { "type": "string" },
                                        "path": { "type": "string" }
                                    }
                                }
                            }
                        } 
                    }
                ]
            }
        }
    }
}

但是:

  1. 这个方案看起来很脏
  2. 这不完全是我想要的

要为其创建架构的JSON架构本身:

{
    "virtual": [
        {
            "type": "bus",
            "path": "VBUS1",
            "entity": "pde",
            "nodes": [
                {
                    "id": "vrt_1",
                    "type": "dispenser",
                    "address": 1,
                    "nozzles": [1, 2, 3]
                },
                {
                    "id": "vrt_2",
                    "type": "dispenser",
                    "address": 2,
                    "nozzles": [4, 5, 3]
                }
            ]
        },
        {
            "type": "bus",
            "path": "VBUS2",
            "entity": "topaz",
            "nodes": [          
                {
                    "uid": 1,
                    "utype": "dispenser",
                    "uaddress": "false",
                    "unozzles": true
                },
                {
                    "uid": 2,
                    "utype": "dispenser",
                    "uaddress": "true",
                    "unozzles": false
                }
            ]
        },
        {
            "type": "io",
            "nodes": [
                "num": 4,
                "key": 123456,
                "title": "io",
                "path": "default"
            ]
        }
    ]
}

完整JSON具有相当复杂的结构,此处仅表示一部分。因此,我想了解如何正确地构造这些东西(理解想法本身,并且最好看一看正确方案的示例。至少是示意图)。

因此,总结一下。我需要了解如何在anyOf变体之一中实现any。可行吗而且,如果是这样,我在哪里可以看到有关编译此类方案的示例和说明?如果没有,有什么解决方法吗?

2 个答案:

答案 0 :(得分:1)

我想我已经找到了解决方案。但是,如果有任何评论或更正,我将很高兴听到。

以防万一,我举一个例子说明这个方案:

{   
    "definitions": {},
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": [
        "virtual"
    ],
    "properties": {
        "virtual": {
            "type": "array",
            "items": {
                "type": "object",
                "required": [
                    "type"
                ],
                "properties": {
                    "type": {
                        "enum": ["bus", "io"]
                    }
                },
                "anyOf": [
                    {       
                        "properties":{
                            "type": {"const": "bus"},                       
                        },
                        "anyOf":[
                            {
                                "properties":{
                                    "path": { "type": "string" },
                                    "entity": {"const": "pde"},
                                    "nodes": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "id",
                                                "type",
                                                "address",
                                                "nozzles"
                                            ],
                                            "properties": {
                                                "id": { "type": "string" },
                                                "type": { "type": "string" },
                                                "address": { "type": "integer" },
                                                "nozzles": {
                                                    "type": "array",
                                                    "items": { "type": "integer" }
                                                }
                                            }
                                        }
                                    }
                                }
                            },
                            {
                                "properties":{
                                    "path": { "type": "string" },
                                    "entity": {"const": "topaz"},
                                    "nodes": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "uid",
                                                "utype",
                                                "uaddress",
                                                "unozzles"
                                            ],
                                            "properties": {
                                                "uid": { "type": "integer" },
                                                "utype": { "type": "string" },
                                                "uaddress": { "type": "string" },
                                                "unozzles": { "type": "boolean" }
                                            }
                                        }
                                    }
                                }
                            }
                        ]
                    },
                    {
                        "properties": {
                            "type": {"const": "io"},
                            "nodes": {
                                "type": "array",
                                "items":{
                                    "type": "object",
                                    "required": [
                                        "num",
                                        "key",
                                        "title",
                                        "path"
                                    ],
                                    "properties": {
                                        "num": { "type": "integer" },
                                        "key": { "type": "integer" },
                                        "title": { "type": "string" },
                                        "path": { "type": "string" }
                                    }
                                }
                            }
                        }
                    }
                ]
            }
        }   
    }
} 

答案 1 :(得分:0)

尽管嵌套的anyOf在JSON模式中可以正常工作,但我认为这不是最好的解决方案。展平anyOf并使用一些definitions可以极大地清理架构,使其更容易推理。

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["virtual"],
  "properties": {
    "virtual": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["type"],
        "anyOf": [
          { "$ref": "#/definitions/pdm" },
          { "$ref": "#/definitions/topaz" },
          { "$ref": "#/definitions/io" }
        ]
      }
    }
  },
  "definitions": {
    "pdm": {
      "properties":{
        "type": { "const": "bus" },
        "entity": { "const": "pde" },
        ... type specific properties ...
      }
    },
    "topaz": {
      "properties": {
        "type": { "const": "bus" },
        "entity": { "const": "topaz" },
        ... type specific properties ...
      }
    },
    "io": {
      "properties": {
        "type": { "const": "io" },
        ... type specific properties ...
      }
    }
  }
}

如果您使用if / then / else或隐含模式而不是枚举模式,则可以获得更好的错误消息传递,但具有更复杂的模式。

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["virtual"],
  "properties": {
    "virtual": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["type"],
        "allOf": [
          { "$ref": "#/definitions/pdm" },
          { "$ref": "#/definitions/topaz" },
          { "$ref": "#/definitions/io" }
        ]
      }
    }
  },
  "definitions": {
    "pdm": {
      "if": {
        "properties":{
          "type": { "const": "bus" },
          "entity": { "const": "pde" }
        },
        "required": ["type", "entity"]
      },
      "then": {
        "properties": {
          ... type specific constraints ...
        }
      }
    },
    ... additional types ...
}