当存在 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 个错误作为数组的一部分(见下文)。为什么?
- 从技术上讲,架构验证器应该在第 2 项处停止,并且应该忽略错误数组中的 'Germany',因为它发现 'Findland' 条目违反了 if-else 条件。
- 此外,模式验证器是否从 '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
部分,而不是每次检查所有国家/地区。例如
- 如果数组包含“USA”条目,则“GERMANY”和“FINLAND”都不应存在(因为您已经有了)
- 如果数组包含“GERMANY”条目,则不应存在“FINLAND”条目(不要再次检查“USA”)
- 如果数组包含“FINLAND”条目,则可能的情况已经包含在上面的两个检查中——这里不需要任何额外的检查。
这样一来,您就不会同时遇到多个此类错误。
这是我的 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 个错误作为数组的一部分(见下文)。为什么?
- 从技术上讲,架构验证器应该在第 2 项处停止,并且应该忽略错误数组中的 'Germany',因为它发现 'Findland' 条目违反了 if-else 条件。
- 此外,模式验证器是否从 '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
部分,而不是每次检查所有国家/地区。例如
- 如果数组包含“USA”条目,则“GERMANY”和“FINLAND”都不应存在(因为您已经有了)
- 如果数组包含“GERMANY”条目,则不应存在“FINLAND”条目(不要再次检查“USA”)
- 如果数组包含“FINLAND”条目,则可能的情况已经包含在上面的两个检查中——这里不需要任何额外的检查。
这样一来,您就不会同时遇到多个此类错误。