NjsonSchema 验证如果 Property1 等于 Something 则需要 Property2
NjsonSchema Validation If Property1 is equal to Something then require Property2
我似乎无法让 const 或 enum 作为 if-then-else JSON 模式验证的一部分工作。
当涉及 1 个验证值时,它们似乎可以互换。 (Reference)
这是我的 JSON 架构
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Test_Schema",
"description": "A schema for validating a test object",
"type": "object",
"additionalProperties": false,
"properties": {
"GeneralData": {
"type": "object",
"description": "Advsor and admin customer information",
"properties": {
"Name": {
"type": [ "string", "null" ],
"description": "Customer's advisor name"
},
"Age": {
"type": [ "string", "null" ],
"description": "Customer's advisor email"
},
"Location": {
"type": [ "string", "null" ],
"description": "The advisor's manager email'"
}
},
"required": [ "Name", "Location", "Age" ]
},
"ClientData": {
"type": "object",
"description": "Customer's information",
"additionalProperties": false,
"properties": {
"Title": {
"type": [ "string", "null" ]
},
"Forename": {
"type": [ "string", "null" ]
},
"Surname": {
"type": [ "string" ]
}
},
"required": [ "Title" ],
"if": {
"properties": {
"Forename": { "enum": [ "Soameonea" ] }
},
"required": [ "Forename" ]
},
"then": { "required": [ "Surname" ] },
"else": false
}
}
}
如果 Forename = "Someone" 我希望必须填写姓氏。
这是我序列化后的 jsonObject:
{
"GeneralData": {
"Name": "Not Relevant",
"Age": "Not Relevant",
"Location": "Not Relevant"
},
"ClientData": {
"Title": "SomeTitle",
"Forename": "Someone",
"Surname": null
}
}
验证码:
internal void ValidateDataObjectOnSchema()
{
var dataObject = PopulateDataObject();
var json = JsonConvert.SerializeObject(dataObject);
var result = GetSchema().Validate(json);
var errors = result.Select(x =>
{
return new Errors() { Title = x.Property, Description = x.Schema.Description };
});
var i = errors;
}
internal JsonSchema GetSchema()
{
return JsonSchema.FromFileAsync("Test/testSchema.json").Result;
}
现在它仍然需要姓氏,即使枚举 Soameonea != Someone and I 只需要 Title。 <== 问题 1
在 JSON 模式中,如果我设置 "Surname":{"type":["string","null]} 那么错误就会消失,但我仍然没有收到错误将 Forename 枚举的 if 条件更改为“某人”。<== 问题 2
如果我将 Enum 替换为 Const,我将无法获得不同的验证输出,因此,如果我能让其中一个起作用,我相信另一个也会随之而来。
我找到了这个问题的几个答案 (),我尝试实现同样的事情,但由于某种原因,我的情况失败了。
我错过了什么?
更新:
正如@Relequestial 在其中一条评论中提到的那样,NJson Schema 似乎只支持 Draft 04,这就是 if-then-else 不起作用的原因,应该使用隐含代替。下面是我使用替代包的解决方案。
相同的代码和 json 可与包 Newtonsoft.Json.Schema (Reference)
一起使用
代码:
internal void ValidateDataObjectOnSchemaWithNewtonSoftJson()
{
var dataObject = PopulateDataObject();
var settings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore
};
var jsonDataObjectString = JsonConvert.SerializeObject(dataObject, settings);
JObject jsonDataObject = JObject.Parse(jsonDataObjectString);
var jsonSchemaFile = File.ReadAllText("Test/testSchema.json");
var schema = JSchema.Parse(jsonSchemaFile);
;
IList<ValidationError> messages;
var result = jsonDataObject.IsValid(schema, out messages);
var errors = GetReadableResult(result, messages);
}
private List<Errors> GetReadableResult(bool result, IList<ValidationError> messages)
{
var errors = new List<Errors>();
if (!result)
{
foreach (var error in messages)
{
if (error.ChildErrors.Count > 0)
{
errors.Add(
new Errors()
{
Path = error.ChildErrors.FirstOrDefault()?.Path,
Kind = error.ChildErrors.FirstOrDefault()?.Message
});
}
else
{
errors.Add(new Errors()
{
Path = error.Path,
Kind = error.Message
});
}
}
}
return errors;
}
JsonSchema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Test_Schema",
"description": "A schema for validating a test object",
"type": "object",
"additionalProperties": false,
"properties": {
"GeneralData": {
"type": "object",
"description": "Advsor and admin customer information",
"properties": {
"Name": {
"type": [ "string", "null" ],
"description": "Customer's advisor name"
},
"Age": {
"type": [ "string", "null" ],
"description": "Customer's advisor email"
},
"Location": {
"type": [ "string", "null" ],
"description": "The advisor's manager email'"
}
},
"required": [ "Name", "Location", "Age" ]
},
"ClientData": {
"type": "object",
"description": "Customer's information",
"additionalProperties": false,
"properties": {
"Title": {
"type": [ "string", "null" ]
},
"Forename": {
"type": "string"
},
"Surname": {
"type": [ "string" ]
}
},
"required": [ "Title" ],
"if": {
"properties": {
"Forename": { "enum": [ "Someone" ] }
},
"required": [ "Forename" ]
},
"then": { "required": [ "Surname" ] },
"else": {}
}
}
}
唯一的补充是使 GetReadableResult 对具有多个子项的错误递归。
In the JSON schema if I set "Surname":{"type":["string","null]} then the error disappears
具有空值的 属性 仍然具有值。如果你想说 属性 值不仅必须存在,而且不能为 null,则将 "type": "string"
添加到你的 then
条件中。
我似乎无法让 const 或 enum 作为 if-then-else JSON 模式验证的一部分工作。
当涉及 1 个验证值时,它们似乎可以互换。 (Reference)
这是我的 JSON 架构
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Test_Schema",
"description": "A schema for validating a test object",
"type": "object",
"additionalProperties": false,
"properties": {
"GeneralData": {
"type": "object",
"description": "Advsor and admin customer information",
"properties": {
"Name": {
"type": [ "string", "null" ],
"description": "Customer's advisor name"
},
"Age": {
"type": [ "string", "null" ],
"description": "Customer's advisor email"
},
"Location": {
"type": [ "string", "null" ],
"description": "The advisor's manager email'"
}
},
"required": [ "Name", "Location", "Age" ]
},
"ClientData": {
"type": "object",
"description": "Customer's information",
"additionalProperties": false,
"properties": {
"Title": {
"type": [ "string", "null" ]
},
"Forename": {
"type": [ "string", "null" ]
},
"Surname": {
"type": [ "string" ]
}
},
"required": [ "Title" ],
"if": {
"properties": {
"Forename": { "enum": [ "Soameonea" ] }
},
"required": [ "Forename" ]
},
"then": { "required": [ "Surname" ] },
"else": false
}
}
}
如果 Forename = "Someone" 我希望必须填写姓氏。
这是我序列化后的 jsonObject:
{
"GeneralData": {
"Name": "Not Relevant",
"Age": "Not Relevant",
"Location": "Not Relevant"
},
"ClientData": {
"Title": "SomeTitle",
"Forename": "Someone",
"Surname": null
}
}
验证码:
internal void ValidateDataObjectOnSchema()
{
var dataObject = PopulateDataObject();
var json = JsonConvert.SerializeObject(dataObject);
var result = GetSchema().Validate(json);
var errors = result.Select(x =>
{
return new Errors() { Title = x.Property, Description = x.Schema.Description };
});
var i = errors;
}
internal JsonSchema GetSchema()
{
return JsonSchema.FromFileAsync("Test/testSchema.json").Result;
}
现在它仍然需要姓氏,即使枚举 Soameonea != Someone and I 只需要 Title。 <== 问题 1
在 JSON 模式中,如果我设置 "Surname":{"type":["string","null]} 那么错误就会消失,但我仍然没有收到错误将 Forename 枚举的 if 条件更改为“某人”。<== 问题 2
如果我将 Enum 替换为 Const,我将无法获得不同的验证输出,因此,如果我能让其中一个起作用,我相信另一个也会随之而来。
我找到了这个问题的几个答案 (
我错过了什么?
更新: 正如@Relequestial 在其中一条评论中提到的那样,NJson Schema 似乎只支持 Draft 04,这就是 if-then-else 不起作用的原因,应该使用隐含代替。下面是我使用替代包的解决方案。
相同的代码和 json 可与包 Newtonsoft.Json.Schema (Reference)
一起使用代码:
internal void ValidateDataObjectOnSchemaWithNewtonSoftJson()
{
var dataObject = PopulateDataObject();
var settings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore
};
var jsonDataObjectString = JsonConvert.SerializeObject(dataObject, settings);
JObject jsonDataObject = JObject.Parse(jsonDataObjectString);
var jsonSchemaFile = File.ReadAllText("Test/testSchema.json");
var schema = JSchema.Parse(jsonSchemaFile);
;
IList<ValidationError> messages;
var result = jsonDataObject.IsValid(schema, out messages);
var errors = GetReadableResult(result, messages);
}
private List<Errors> GetReadableResult(bool result, IList<ValidationError> messages)
{
var errors = new List<Errors>();
if (!result)
{
foreach (var error in messages)
{
if (error.ChildErrors.Count > 0)
{
errors.Add(
new Errors()
{
Path = error.ChildErrors.FirstOrDefault()?.Path,
Kind = error.ChildErrors.FirstOrDefault()?.Message
});
}
else
{
errors.Add(new Errors()
{
Path = error.Path,
Kind = error.Message
});
}
}
}
return errors;
}
JsonSchema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Test_Schema",
"description": "A schema for validating a test object",
"type": "object",
"additionalProperties": false,
"properties": {
"GeneralData": {
"type": "object",
"description": "Advsor and admin customer information",
"properties": {
"Name": {
"type": [ "string", "null" ],
"description": "Customer's advisor name"
},
"Age": {
"type": [ "string", "null" ],
"description": "Customer's advisor email"
},
"Location": {
"type": [ "string", "null" ],
"description": "The advisor's manager email'"
}
},
"required": [ "Name", "Location", "Age" ]
},
"ClientData": {
"type": "object",
"description": "Customer's information",
"additionalProperties": false,
"properties": {
"Title": {
"type": [ "string", "null" ]
},
"Forename": {
"type": "string"
},
"Surname": {
"type": [ "string" ]
}
},
"required": [ "Title" ],
"if": {
"properties": {
"Forename": { "enum": [ "Someone" ] }
},
"required": [ "Forename" ]
},
"then": { "required": [ "Surname" ] },
"else": {}
}
}
}
唯一的补充是使 GetReadableResult 对具有多个子项的错误递归。
In the JSON schema if I set "Surname":{"type":["string","null]} then the error disappears
具有空值的 属性 仍然具有值。如果你想说 属性 值不仅必须存在,而且不能为 null,则将 "type": "string"
添加到你的 then
条件中。