C# 使用JSON模式,在将JSON解析为JObject时,如何过滤掉其他属性?
我试图只解析提供的JSON的一部分。我正在使用Newtonsoft.Json.Schema nuget。 对于下一个示例,我只想反序列化name和age属性C# 使用JSON模式,在将JSON解析为JObject时,如何过滤掉其他属性?,c#,json,json.net,jsonschema,json-deserialization,C#,Json,Json.net,Jsonschema,Json Deserialization,我试图只解析提供的JSON的一部分。我正在使用Newtonsoft.Json.Schema nuget。 对于下一个示例,我只想反序列化name和age属性 JSchema schema = JSchema.Parse(@"{ 'id': 'person', 'type': 'object', 'additionalProperties' : false, 'properties': { 'name': {'type':'string'}, 'age
JSchema schema = JSchema.Parse(@"{
'id': 'person',
'type': 'object',
'additionalProperties' : false,
'properties': {
'name': {'type':'string'},
'age': {'type':'integer'}
}
}");
JsonTextReader reader = new JsonTextReader(new StringReader(@"{
'name': 'James',
'age': 29,
'salary': 9000.01,
'jobTitle': 'Junior Vice President'
}"));
JSchemaValidatingReader validatingReader = new JSchemaValidatingReader(reader);
validatingReader.Schema = schema;
JsonSerializer serializer = new JsonSerializer();
JObject data = serializer.Deserialize<JObject>(validatingReader);
JSchema schema=JSchema.Parse(@){
“id”:“person”,
“类型”:“对象”,
“additionalProperties”:false,
“属性”:{
'name':{'type':'string'},
'age':{'type':'integer'}
}
}");
JsonTextReader reader=新JsonTextReader(新StringReader(@){
'姓名':'詹姆斯',
年龄:29岁,,
“工资”:9000.01,
“职务头衔”:“初级副总裁”
}"));
JSChemAvalidangReader validatingReader=新的JSChemAvalidangReader(读取器);
validatingReader.Schema=Schema;
JsonSerializer serializer=新的JsonSerializer();
JObject data=serializer.Deserialize(validatingReader);
如果我将设置“additionalProperties”:true
我将反序列化不必要的字段
但是如果我将设置“additionalProperties”:false,我将收到一个错误:
Newtonsoft.Json.Schema.JSchemaValidationException:尚未定义属性“salary”,并且架构不允许其他属性。路径“工资”,第4行,职位11。
请注意,我将只在运行时知道所需的字段。我收到了大的JSON,我需要创建一些解决方案来反序列化这个JSON的一部分。用户应该决定哪些属性应该被处理,哪些属性不应该被处理。我认为没有任何内置的方法用于您的用例,因为additionalProperties
意味着禁止/允许附加属性。但一旦模式中允许它们,它们也会被反序列化。在模式中允许附加属性对我来说没有多大意义,但是不允许它们显示在数据中。也许你可以解释一下你的用例
最简单的可能是反序列化到类,而不是JObject
。在该类中,只定义您希望看到的属性
class Person {
[JsonProperty("name")];
public string Name {get;set;}
[JsonProperty("age")];
public int Age {get;set;}
}
...
Person p = serializer.Deserialize<Person>(validatingReader);
班级人员{
[JsonProperty(“名称”)];
公共字符串名称{get;set;}
[JsonProperty(“年龄”)];
公共整数{get;set;}
}
...
Person p=序列化程序。反序列化(validatingReader);
表示提供JSchema验证的读取器。它不提供任何类型的过滤功能
相反,您可以将JSON加载到JToken
中,使用进行验证,然后在指定的路径上删除其他属性
为此,请按如下方式修改代码:
var data = JObject.Parse(jsonString); // The string literal from your question
var isValid = data.IsValid(schema, out IList<ValidationError> errors);
if (!isValid)
{
foreach (var error in errors)
{
if (error.ErrorType == ErrorType.AdditionalProperties)
data.SelectToken(error.Path)?.RemoveFromLowestPossibleParent();
}
}
注:
- 当错误类型为
ErrorType.AdditionalProperties
时,路径将直接指向不需要的属性,但对于其他错误类型,如路径,则可能指向父容器。因此,在移除与给定路径上的错误相关的令牌之前,应该检查错误类型
- 如果您的JSON很大,建议您使用
JsonSerializer.CreateDefault()。直接从流中反序列化。反序列化(读取器)
(正如您当前所做的),以避免将JSON加载到中间字符串中
演示小提琴。不确定这是否有效,但尝试使用'allowAdditionalProperties':true
而不是'additionalProperties':true
@Thomas如果我使用'allowAdditionalProperties':false
,它仍然会解析工资和职务属性。但我不想在结果中看到它们这是我的主要问题,我只会在运行时知道所需的字段。我收到了大的JSON,我需要创建一些解决方案来反序列化这个JSON的一部分。用户应该决定哪些属性应该处理,哪些不应该。也许您有一些其他的解决方案,而不是使用JSchema?当然,您可以在运行时创建具有所需属性的类型,如此处所示,或者您可以在反序列化后对数据对象进行后处理,并删除所有不需要的属性。但我不认为有任何可能只是“部分”反序列化json字符串。乍一看,它是有效的。我将尝试更多的案例,然后将您的评论标记为答案。非常感谢你!
public static partial class JsonExtensions
{
public static JToken RemoveFromLowestPossibleParent(this JToken node)
{
if (node == null)
return null;
// If the parent is a JProperty, remove that instead of the token itself.
var property = node.Parent as JProperty;
var contained = property ?? node;
if (contained.Parent != null)
contained.Remove();
// Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
if (property != null)
property.Value = null;
return node;
}
}