JSON-Schema oneOf用于根区域下的选项

时间:2017-12-21 13:51:39

标签: json jsonschema

我正试图获得" oneof"允许根项目中的选项,但无法找到一个示例,我尝试给出一个错误。 如果它在另一个项目下但不在根目录下,我可以让它工作{' s

示例 - 具有必填字段(jobNum,收款人,金额,类型)和付款类型选项(checkInfo或dollarAmt)的工作付款。我知道这可以通过其他方式完成,但我需要这种方法来实现更复杂的模式。

{
    "jobNum": "x216",
    "payee": "John Doe",
    "type": "check",
    "amount": "112.25",
    "checkInfo": {
        "number": "386"
    }
}
{
    "JobNum": "x216",
    "Payee": "John Doe",
    "type" : "Cash",    
    "amount" : "112.25",
    "cashInfo" : {
        "dollarAmt" : "112",
        "coinAmt" : "0.25"
    }   
}

以下内容给出了我的错误 - "在读取' oneOf'的值时遇到了意外的令牌。预期的StartObject,Boolean,得到了StartArray"

{
    "description": "Job Payment",
    "type": "object",
    "required": [ "jobNum", "payee", "amount", "type"],
    "properties": {
        "jobNum": {
            "type": "string"
        },
        "payee": {
            "type": "string"
        },
        "amount": {
            "type": "string"
        },
        "type": {"enum": [ "check", "cash" ]
        },
        "oneOf": [
            { "$ref": "#/definitions/ptCash" },
            { "$ref": "#/definitions/ptCheck" }
        ]
    },
    "definitions": {
        "ptCash": {
            "properties": {
                "checkInfo": {
                    "number": "string"
                }
            },
            "required": [ "checkInfo" ],
            "additionalProperties": false
        },
        "ptCheck": {
            "properties": {
                "dollarAmt": { 
                    "type": "string"
                },
                "coinAmt": {
                    "type": "string"
                }
            },
            "required": [ "dollarAmt", "coinAmt" ],
            "additionalProperties": false
        }
    },
    "additionalProperties": false
}

2 个答案:

答案 0 :(得分:2)

您的架构存在一些问题。我在下面为你修好了。我不会解释我所做的所有更改,因为我认为通过阅读架构非常清楚。如果您想了解更多关于任何事情的详细信息,请询问,我将更新答案并提供更多详细信息。

oneOf关键字只能出现在架构中。 properties关键字是一个对象,其值为模式。当您将“oneOf”直接放在properties下时,它不会被解释为关键字,它会被解释为名为“oneOf”的属性。然后验证器会抱怨,因为属性“oneOf”的值应该是一个模式,而不是像oneOf关键字那样的模式数组。

您对additionalProperties的使用不起作用。这个关键字不像人们通常认为的那样有效。 JSON Schema关键字不知道它们所在模式之外的任何状态。让我们先看看oneOf的“ptCheck”分支。这描述了属性“数字”,表示它是必需的,并且可能没有“数字”以外的关键字。然后您的顶级定义属性“jobNum”,“payee”,“amount”和“type”,需要它们all并且不允许其他属性。这两件事永远不可能同时存在。即使您的架构有效,也没有对该架构有效的JSON值。这就是为什么我将“checkInfo”和“cashInfo”的定义移到顶层,只将required部分放在oneOf中。这种方法的唯一缺点是你可以传递“checkInfo”和“cachInfo”对象,它将验证。外来属性被忽略。有很多方法,但它们有问题,我不建议使用它们。

我总是建议人们不要使用"additionalProperties": false而忽略未知属性。原因是JSON Schema是一个约束系统。任何有效的JSON对空模式({})都有效,并且模式中的每个关键字都会添加一些约束。这是人们在定义类时习惯的不同方法。空类不描述任何内容,并添加有效值。我们使用"additionalProperties": false来使JSON Schema更像是定义一个类,但是试图让JSON Schema表现得像它不会引起像你在这里看到的那样的挑战。

{
  "description": "Job Payment",
  "type": "object",
  "required": ["jobNum", "payee", "amount", "type"],
  "properties": {
    "jobNum": { "type": "string" },
    "payee": { "type": "string" },
    "amount": { "type": "string" },
    "type": { "enum": ["check", "cash"] },
    "checkInfo": {
      "type": "object",
      "properties": {
        "number": { "type": "string" }
      },
      "required": ["number"]
    },
    "cashInfo": {
      "type": "object",
      "properties": {
        "dollarAmt": { "type": "string" },
        "coinAmt": { "type": "string" }
      },
      "required": ["dollarAmt", "coinAmt"]
    }
  },
  "oneOf": [
    { "$ref": "#/definitions/ptCash" },
    { "$ref": "#/definitions/ptCheck" }
  ],
  "definitions": {
    "ptCheck": {
      "type": "object",
      "properties": {
        "type": { "enum": ["check"] }
      },
      "required": ["checkInfo"]
    },
    "ptCash": {
      "type": "object",
      "properties": {
        "type": { "enum": ["cash"] }
      },
      "required": ["cashInfo"]
    }
  },
  "additionalProperties": false
}

答案 1 :(得分:1)

  1. oneOf应放在prope中
  2. 必须使用ptCash重新编写ptChecktype: object的规则
  3. 以下架构应与ptCheck

    一起使用
    {
        "description": "Job Payment",
        "type": "object",
        "required": [ "jobNum", "payee", "amount", "type"],
        "properties": {
            "jobNum": {
                "type": "string"
            },
            "payee": {
                "type": "string"
            },
            "amount": {
                "type": "string"
            },
            "type": {"enum": [ "check", "cash" ]
            }
        },
        "oneOf": [
                { "$ref": "#/definitions/ptCash" },
                { "$ref": "#/definitions/ptCheck" }
        ],
        "definitions": {
            "ptCash": {
                "properties": {
                    "checkInfo": {
                        "type": "object",
                        "required": ["number"],
                        "properties": {
                            "number": {
                                "type": "string"
                            }
                        }
                    }
                },
                "required": [ "checkInfo" ]
            },
            "ptCheck": {
                "properties": {
                    "cashInfo": {
                        "type": "object",
                        "properties": {
                            "dollarAmt": {
                                "type": "string"
                            },
                            "coinAmt": {
                                "type": "string"
                            }
                        },
                        "required": ["dollarAmt", "coinAmt"]
                    }
                },
                 "required": ["cashInfo"]
            }
        }
    }
    

    提供如下示例:

    import jsonschema
    import simplejson as json
    
    schema_filename = '47926398.json'
    with open(schema_filename, 'r') as f:
        schema_data = f.read()
    schema = json.loads(schema_data)
    
    # validate with checkInfo
    json_obj = {
        "jobNum": "x216",
        "payee": "John Doe",
        "type": "check",
        "amount": "112.25",
        "checkInfo": {
            "number": "386"
        }
    }
    jsonschema.validate(json_obj, schema)
    
    
    # invalidate
    json_obj = {
        "jobNum": "x216",
        "payee": "John Doe",
        "type": "check",
        "amount": "112.25",
        "checkInfox": {
            "number": "386"
        }
    }
    jsonschema.validate(json_obj, schema)
    
    
    # validate with cashInfo
    json_obj = {
        "jobNum": "x216",
        "payee": "John Doe",
        "type": "check",
        "amount": "112.25",
        "cashInfo": {
            "dollarAmt": "400",
            "coinAmt": "30"
        }
    }
    jsonschema.validate(json_obj, schema)
    
    # invalidate with cashInfo
    json_obj = {
        "jobNum": "x216",
        "payee": "John Doe",
        "type": "check",
        "amount": "112.25",
        "cashInfox": {
            "dollarAmt": "400",
            "coinAmt": "30"
        }
    }
    jsonschema.validate(json_obj, schema)
    
    # invalidate with cashInfo.dollarAmtx
    json_obj = {
        "jobNum": "x216",
        "payee": "John Doe",
        "type": "check",
        "amount": "112.25",
        "cashInfo": {
            "dollarAmtx": "400",
            "coinAmt": "30"
        }
    }
    jsonschema.validate(json_obj, schema)