当存在 if-else 时,JSON 架构验证器的额外错误消息

Extra error message by JSON Schema validator when if-else is there

这是我的 JSON 架构(假设的,因为我无法分享我的实际架构)和 JSON。 if-then-else 条件如下:

一次只有三 (3) 个国家/地区中的一 (1) 个国家可以定义统计数据。

架构

    {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "type": "object",
        "required": [
            "year",
            "country",
            "statistics"
        ],
        "definitions": {
        "statisticsUsa": {
          "if": {
            "properties": {
              "type": {
                "const": "statisticsUsa"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "properties": {
              "type": {
                "const": "statisticsUsa"
              }
            }
          }
        },
            "statisticsFinland": {
          "if": {
            "properties": {
              "type": {
                "const": "statisticsFinland"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "properties": {
              "type": {
                "const": "statisticsFinland"
              }
            }
          }
        },
        "statisticsGermany": {
          "if": {
            "properties": {
              "type": {
                "const": "statisticsGermany"
              }
            },
            "required": [
              "type", "literacy"
            ]
          },
          "then": {
            "properties": {
              "type": {
                "const": "statisticsGermany"
              },
              "literacy": {
                "type": "string"
              }
            }
          }
        }
        },
        "properties": {
            "year": {
                "type": "string"
            },
            "country": {
                "type": "string",
                "enum": [
                    "USA",
                    "FINLAND",
                    "GERMANY"
                ]
            },
            "statistics": {

                "type": "array",
                "allOf": [{
                        "if": {
                            "contains": {
                                "type": "object",
                                "properties": {
                                    "type": {
                                        "type": "string",
                                        "enum": [
                                            "statisticsUsa"
                                        ]
                                    }
                                }
                            }
                        },
                        "then": {
                            "not": {
                                "contains": {
                                    "type": "object",
                                    "properties": {
                                        "type": {
                                            "type": "string",
                                            "enum": [
                                                "statisticsFinland",
                                                "statisticsGermany"
                                            ]
                                        }
                                    }
                                }
                            }
                        },"errorMessage" :"Only USA applicable at a time for statistics"
                    },
                    {
                        "if": {
                            "contains": {
                                "type": "object",
                                "properties": {
                                    "type": {
                                        "type": "string",
                                        "enum": [
                                            "statisticsFinland"
                                        ]
                                    }
                                }
                            }
                        },
                        "then": {
                            "not": {
                                "contains": {
                                    "type": "object",
                                    "properties": {
                                        "type": {
                                            "type": "string",
                                            "enum": [
                                                "statisticsUsa",
                                                "statisticsGermany"
                                            ]
                                        }
                                    }
                                }
                            }
                        },"errorMessage" :"Only Finland applicable at a time for statistics"
                    },
                    {
                        "if": {
                            "contains": {
                                "type": "object",
                                "properties": {
                                    "type": {
                                        "type": "string",
                                        "enum": [
                                            "statisticsGermany"
                                        ]
                                    }
                                }
                            }
                        },
                        "then": {
                            "not": {
                                "contains": {
                                    "type": "object",
                                    "properties": {
                                        "type": {
                                            "type": "string",
                                            "enum": [
                                                "statisticsUsa",
                                                "statisticsFinland"
                                            ]
                                        }
                                    }
                                }
                            }
                        },"errorMessage" :"Only Germany applicable at a time for statistics"
                    }

                ],
                "minItems": 1,
                "items": {
                    "anyOf": [{
                            "$ref": "#/definitions/statisticsUsa"
                        },
                        {
                            "$ref": "#/definitions/statisticsFinland"
                        },
                        {
                            "$ref": "#/definitions/statisticsGermany"
                        }
                    ]
                }
            }
        }
    }

Json 1

    const Ajv = require('ajv');
    const ajv = new Ajv({
        allErrors: true,
        jsonPointers: true
    });

    const schema1 = require("./sof.json");
    require('ajv-errors')(ajv /*, {singleError: true} */);
    const data = {
      year: "2000",
      country: "USA",
      statistics: [
        {"type":"statisticsUsa"},
        {"type":"statisticsFinland"}
      ]
    }

    let valid = ajv.validate(schema1, data); //schema, data
    if (!valid) {
      console.log(`${JSON.stringify(ajv.errors,null,2)}`);
    }

在这里,当我有 2 个国家/地区时,我可以看到 2 个错误作为数组的一部分。我的问题是,'finland' 不能与 'USA' 一起使用,"Only USA applicable at a time for statistics" 的错误是不可接受的,因为它满足条件。但是,Findland 的错误是可以接受的。

    [
      {
        "keyword": "errorMessage",
        "dataPath": "/statistics",
        "schemaPath": "#/properties/statistics/allOf/0/errorMessage",
        "params": {
          "errors": [
            {
              "keyword": "not",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/0/then/not",
              "params": {},
              "message": "should NOT be valid"
            },
            {
              "keyword": "if",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/0/if",
              "params": {
                "failingKeyword": "then"
              },
              "message": "should match \"then\" schema"
            }
          ]
        },
        "message": "Only USA applicable at a time for statistics"
      },
      {
        "keyword": "errorMessage",
        "dataPath": "/statistics",
        "schemaPath": "#/properties/statistics/allOf/1/errorMessage",
        "params": {
          "errors": [
            {
              "keyword": "not",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/1/then/not",
              "params": {},
              "message": "should NOT be valid"
            },
            {
              "keyword": "if",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/1/if",
              "params": {
                "failingKeyword": "then"
              },
              "message": "should match \"then\" schema"
            }
          ]
        },
        "message": "Only Finland applicable at a time for statistics"
      }
    ]

此外,如果我在 JSON 中添加 'Germany' 作为

{
  year: "2000",
  country: "USA",
  statistics: [
    {"type":"statisticsUsa"},
    {"type":"statisticsFinland"},
    {"type":"statisticsGermany"}
  ]
}

它抛出 3 个错误作为数组的一部分(见下文)。为什么?

  1. 从技术上讲,架构验证器应该在第 2 项处停止,并且应该忽略错误数组中的 'Germany',因为它发现 'Findland' 条目违反了 if-else 条件。
  2. 此外,模式验证器是否从 'statistics' 数组(来自 JSON)中获取每个项目并检查每个 运行 的 'allOf' 中的条件,这就是为什么数组中有 3 个错误条目。我的理解对吗。 (如果您看到上面的第一个错误数组,它只有 2 个条目)

    [
      {
        "keyword": "errorMessage",
        "dataPath": "/statistics",
        "schemaPath": "#/properties/statistics/allOf/0/errorMessage",
        "params": {
          "errors": [
            {
              "keyword": "not",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/0/then/not",
              "params": {},
              "message": "should NOT be valid"
            },
            {
              "keyword": "if",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/0/if",
              "params": {
                "failingKeyword": "then"
              },
              "message": "should match \"then\" schema"
            }
          ]
        },
        "message": "Only USA applicable at a time for statistics"
      },
      {
        "keyword": "errorMessage",
        "dataPath": "/statistics",
        "schemaPath": "#/properties/statistics/allOf/1/errorMessage",
        "params": {
          "errors": [
            {
              "keyword": "not",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/1/then/not",
              "params": {},
              "message": "should NOT be valid"
            },
            {
              "keyword": "if",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/1/if",
              "params": {
                "failingKeyword": "then"
              },
              "message": "should match \"then\" schema"
            }
          ]
        },
        "message": "Only Finland applicable at a time for statistics"
      },
      {
        "keyword": "errorMessage",
        "dataPath": "/statistics",
        "schemaPath": "#/properties/statistics/allOf/2/errorMessage",
        "params": {
          "errors": [
            {
              "keyword": "not",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/2/then/not",
              "params": {},
              "message": "should NOT be valid"
            },
            {
              "keyword": "if",
              "dataPath": "/statistics",
              "schemaPath": "#/properties/statistics/allOf/2/if",
              "params": {
                "failingKeyword": "then"
              },
              "message": "should match \"then\" schema"
            }
          ]
        },
        "message": "Only Germany applicable at a time for statistics"
      }
    ]

您自己已经推导出来:allOf contains 应用所有子模式并检查所有数组项。

如果您只想要一条错误消息,那么您应该决定国家/地区的优先级,并且只检查其余国家/地区的后续 allOf 部分,而不是每次检查所有国家/地区。例如

  1. 如果数组包含“USA”条目,则“GERMANY”和“FINLAND”都不应存在(因为您已经有了)
  2. 如果数组包含“GERMANY”条目,则不应存在“FINLAND”条目(不要再次检查“USA”)
  3. 如果数组包含“FINLAND”条目,则可能的情况已经包含在上面的两个检查中——这里不需要任何额外的检查。

这样一来,您就不会同时遇到多个此类错误。