JSON-schema oneOf for option under root area

JSON-Schema oneOf for option under root area

我正在尝试让 "oneof" 允许在根项中使用选项,但找不到示例,我尝试的操作给出了错误。 如果它在另一个项目下但不在根 {'s

下,我可以让它工作

示例 - 具有必填字段(jobNum、payee、amount、type,)和付款类型选项(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"
    }   
}

以下给出了这个错误 - "Unexpected token encountered when reading value for 'oneOf'. Expected StartObject, Boolean, got 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
}
  1. oneOf应该放在prope
  2. 必须使用 type: object
  3. ptCashptCheck 重写规则

以下架构应与 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)

您的架构存在一些问题。我在下面为您修复了它。我不会解释我所做的所有更改,因为我认为通过阅读架构,大部分内容都非常清楚。如果您想了解更多详细信息,请直接提问,我会用更多详细信息更新答案。

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

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

我总是建议人们不要使用 "additionalProperties": false 而是忽略未知属性。原因是 JSON Schema 是一个约束系统。任何有效的 JSON 都对空模式 ({}) 有效,并且模式中的每个关键字都会添加一些约束。这与人们在定义 classes 时习惯使用的方法不同。空 class 不描述任何内容并添加有效值。我们使用 "additionalProperties": false 让 JSON Schema 的行为更像定义 class,但试图让 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
}