【问题标题】:How to use oneOf alongside a common sub-schema (V4)如何将 oneOf 与通用子模式 (V4) 一起使用
【发布时间】:2015-10-11 03:53:25
【问题描述】:

我在尝试创建同时使用 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"
]
}

{
    "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"
    ]
}

【问题讨论】:

    标签: json schema jsonschema


    【解决方案1】:

    我建议不要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"]
    }
    

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

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

    现在的问题是当referenceTypepersonpersonIdreferenceTypevehicle 时,additionalProperties 不再排除vehicleId。为了确保不允许这样做,我添加了 not 子句。

    如果您要添加第三个变体,限制其他属性会变得更加困难。这不仅仅是在anyof 模式数组中添加一个额外的referenceType。您还必须向主架构添加新属性,并为现有referenceTypes所有 禁用这些新类型。您必须在整个架构上进行更改,而不仅仅是正在更改的区域。这就是为什么将additionalProperties 设置为false 通常不是最好的主意。

    【讨论】:

    • 感谢@Jason,这似乎可行。 additionalProperties 肯定不会像我预期的那样工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-02
    • 2015-12-06
    • 2017-06-09
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    相关资源
    最近更新 更多