如何使用oneOf和公共子模式(V4)

时间:2015-07-21 15:27:41

标签: json schema jsonschema

我在尝试创建一个使用oneOf和公共引用的子模式的模式时遇到了麻烦,以避免必须复制模式的某些部分。 架构应该验证的JSON如下所示:

{
  "createdDate": "2015-01-20T17:10:05Z",
  "createdBy": "testUser",
  "lastModifiedDate": "2015-01-20T17:10:05Z",
  "lastModifiedBy": "testUser",
  "fileUrl": {
    "path": "/path/to/file",
    "fileName": "file.pdf"
  },
  "referenceType": "person",
  "fileType": "certificate",
  "personId": "12345"
}

由此,共同部分是:

{
  "createdDate": "2015-01-20T17:10:05Z",
  "createdBy": "testUser",
  "lastModifiedDate": "2015-01-20T17:10:05Z",
  "lastModifiedBy": "testUser",
  "fileUrl": {
    "path": "/path/to/file",
    "fileName": "file.pdf"
  }
}

其余3个字段的名称始终相同且都是必需的,但它们允许的枚举值会有所不同。

因此剩下的3的架构可能是以下之一:

{
"properties": {
    "referenceType": {
        "type": "string",
        "enum": [
            "vehicle"
        ]
    },
    "fileType": {
        "type": "string",
        "enum": [
            "registration document"
        ]
    },
    "vehicleId": {
        "type": "string",
        "pattern": "[^ ]"
    }
},
"required": [
    "vehicleId"
]
}

OR

{
    "properties": {
        "referenceType": {
            "type": "string",
            "enum": [
                "person"
            ]
        },
        "fileType": {
            "type": "string",
            "enum": [
                "certificate"
            ]
        },
        "personId": {
            "type": "string",
            "pattern": "[^ ]"
        }
    },
    "required": [
        "personId"
    ]
}

我似乎无法创建一个模式,我可以避免重复公共字段,并拥有oneOf,并在整个模式中将additionalProperties设置为false。 在下面的示例中,尝试将additionalProperties设置为false会导致验证错误。是否有可能做我想做的事情?

{
    "type": "object",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "definitions": {
        "commonFile": {
            "properties": {
                "createdDate": {
                    "type": "string",
                    "format": "date-time"
                },
                "createdBy": {
                    "type": "string",
                    "pattern": "[^ ]"
                },
                "lastModifiedDate": {
                    "type": "string",
                    "format": "date-time"
                },
                "lastModifiedBy": {
                    "type": "string",
                    "pattern": "[^ ]"
                },
                "fileUrl": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                        "path": {
                            "type": "string",
                            "pattern": "[^ ]"
                        },
                        "fileName": {
                            "type": "string",
                            "pattern": "[^ ]"
                        }
                    },
                    "required": [
                        "path",
                        "fileName"
                    ]
                }
            }   
        }
    },
    "oneOf": [{
            "allOf": [
                {"$ref": "#/definitions/commonFile"}, 
                {
                    "properties": {
                        "referenceType": {
                            "type": "string",
                            "enum": [
                                "person"
                            ]
                        },
                        "fileType": {
                            "type": "string",
                            "enum": [
                                "certificate"
                            ]
                        },
                        "personId": {
                            "type": "string",
                            "pattern": "[^ ]"
                        }
                    },
                    "required": [
                        "personId"
                    ]
                }
            ]
        }, {
            "allOf": [
                {"$ref": "#/definitions/commonFile"}, 
                {
                    "properties": {
                        "referenceType": {
                            "type": "string",
                            "enum": [
                                "vehicle"
                            ]
                        },
                        "fileType": {
                            "type": "string",
                            "enum": [
                                "registration document"
                            ]
                        },
                        "vehicleId": {
                            "type": "string",
                            "pattern": "[^ ]"
                        }
                    },
                    "required": [
                        "vehicleId"
                    ]
                }
            ]
        }
    ],
    "required": [
        "createdDate",
        "createdBy",
        "lastModifiedDate",
        "lastModifiedBy",
        "fileUrl",
        "referenceType",
        "fileType"
    ]
}

1 个答案:

答案 0 :(得分:0)

我建议additionalProperties设置为false。通常最好只是静静地忽略未定义的属性。您需要采取以下架构来实现目标。

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "createdDate": { "type": "string", "format": "date-time" },
    "createdBy": { "type": "string", "pattern": "[^ ]" },
    "lastModifiedDate": { "type": "string", "format": "date-time" },
    "lastModifiedBy": { "type": "string", "pattern": "[^ ]" },
    "fileUrl": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "path": { "type": "string", "pattern": "[^ ]" },
        "fileName": { "type": "string", "pattern": "[^ ]" }
      },
      "required": ["path", "fileName"]
    },
    "referenceType": { "type": "string" },
    "fileType": { "type": "string" },
    "personId": {},
    "vehicleId": {}
  },
  "additionalProperties": false,
  "anyOf": [
    {
      "properties": {
        "referenceType": { "enum": ["person"] },
        "fileType": { "enum": ["certificate"] },
        "personId": { "type": "string", "pattern": "[^ ]" }
      },
      "required": ["personId"],
      "not" : { "required": ["vehicleId"] }
    },
    {
      "properties": {
        "referenceType": { "enum": ["vehicle"] },
        "fileType": { "enum": ["registration document"] },
        "vehicleId": { "type": "string", "pattern": "[^ ]" }
      },
      "required": ["vehicleId"],
      "not" : { "required": ["personId"] }
    }
  ],
  "required": ["createdDate", "createdBy", "lastModifiedDate", "lastModifiedBy", "fileUrl", "referenceType", "fileType"]
}

我做的第一件事是删除所有无关的allOf。只需要一个anyOf。我在主模式中定义了公共属性。变体在anyOf子句中描述。

如果您将additionalProperties设置为false,则其他架构(例如allOfoneOfanyOf)无法引入新属性。这意味着此架构中允许的所有属性都必须包含在声明additionalPropertiesfalse的架构中。这就是我在主模式中声明referenceTypefileTypepersonIdvechicleId的原因。

现在的问题是,当additionalPropertiesvehicleId时,referenceType不再排除person personId referenceType vehicle not }。为了确保不允许这样做,我添加了referenceType条款。

如果您添加第三个变体,限制其他属性会变得更加困难。它不只是向anyof架构数组添加额外的referenceTypes。您还必须向主架构添加新属性,并禁止现有additionalProperties所有的新类型。您必须在架构上进行更改,而不仅仅是正在更改的区域。这就是将false设置为{{1}}通常不是最佳选择的原因。