问题描述
我正在尝试仅解析提供的JSON的一部分.我正在使用Newtonsoft.Json.Schema nuget.对于下一个示例,我只想反序列化name和age属性.
I am trying to parse only part of provided JSON. I am using Newtonsoft.Json.Schema nuget.For the next example, I want to deserialize only name and age properties.
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);
如果我将'additionalProperties'设置为true:
,我会反序列化不必要的字段.
If I will set 'additionalProperties' : true
I will get unnecessary fields deserialized.
但是如果我将'additionalProperties'设置为:false
,则会收到错误消息:
But if I will set 'additionalProperties' : false
, I will receive an error:
Newtonsoft.Json.Schema.JSchemaValidationException:属性"salary"尚未定义,并且该架构不允许其他属性.路径工资",第4行,位置11.
请注意,我只会在运行时知道所需的字段.我收到了很大的JSON,我需要创建一些解决方案以仅反序列化此JSON的一部分.用户应该决定应该处理哪些属性,哪些不应该.
Note that I will know the needed fields only in runtime. I receive big JSON and I need to create some solution to deserialize only part of this JSON. And users should decide which properties should be processed and which aren't.
推荐答案
JSchemaValidatingReader
表示提供JSchema 验证的阅读器.它不提供任何过滤功能.
JSchemaValidatingReader
Represents a reader that provides JSchema validation. It does not provide any sort of filtering capability.
您可以做的是将JSON加载到 JToken
中,并使用 SchemaExtensions.IsValid(JToken,JSchema,out IList< ValidationError>)
,然后在 ValidationError.Path
.
What you could do instead is to load your JSON into a JToken
, validate with SchemaExtensions.IsValid(JToken, JSchema, out IList<ValidationError>)
, and then remove additional properties at the path indicated by ValidationError.Path
.
为此,请按如下所示修改您的代码:
To do this, modify your code as follows:
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();
}
}
使用扩展方法:
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;
}
}
注意:
-
当错误类型为
ErrorType.AdditionalProperties
时,Path
将直接指向不需要的属性,但对于其他错误类型,例如ErrorType.Required
路径可能指向父容器.因此,您应该在删除与给定路径上的错误相关的标记之前检查错误类型.
When the error type is
ErrorType.AdditionalProperties
thePath
will point directly to the unwanted property, but for other error types such asErrorType.Required
the path may point to the parent container. Thus you should check the error type before removing a token related to an error at a given path.
如果您的JSON很大,建议直接使用 JsonSerializer.CreateDefault().Deserialize< JToken>(阅读器)
从流中反序列化(如您目前所做的那样)避免将JSON加载到中间字符串中.
If your JSON is large, it is recommended to deserialize directly from a stream using JsonSerializer.CreateDefault().Deserialize<JToken>(reader)
(as you are doing currently) to avoid loading the JSON into an intermediate string.
演示小提琴此处.
这篇关于使用JSON模式,将JSON解析为JObject时如何过滤掉其他属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!