C# 使用JToken处理空值时基于父条件选择子元素
我正在尝试使用Newtonsoft和C# 使用JToken处理空值时基于父条件选择子元素,c#,json.net,C#,Json.net,我正在尝试使用Newtonsoft和JTokens过滤我的JSON对象。我需要根据父元素的条件选择数组中的子元素。此外,将被筛选的数组可能有空的子元素 以下是JSON对象: { "level1": [{ "id": 1, "level2": [{ "attr": "attrvalue" }, { "attr": "attrvalue",
JToken
s过滤我的JSON对象。我需要根据父元素的条件选择数组中的子元素。此外,将被筛选的数组可能有空的子元素
以下是JSON对象:
{
"level1": [{
"id": 1,
"level2": [{
"attr": "attrvalue"
},
{
"attr": "attrvalue",
"level3": [{
"attr1": "attr1value",
"level4": [{
"filterAttr": ["val1"],
"attr1": "attr1value"
}]
},
{
"attr1": "attr1value",
"level4": [{
"filterAttr": ["val1"],
"attr1": "attr1value",
"level5": [{
"key": "key",
"value": "value"
}]
}]
}
]
}
]
}]
}
我现在使用下面的代码来过滤上面的JSON。我需要根据level4
中val1
的filteratr
从level5
获取键和值
var jToken=jToken.Parse(json);
var key=jToken[“level1”]
.SelectMany(x=>x[“level2”])
。其中(x=>x[“level3”]!=null)
.SelectMany(x=>x[“level3”])
。其中(x=>x[“level4”]!=null)
.SelectMany(x=>x[“level4”])
.Where(x=>Convert.ToString(x[“filteratr”])==filterParam&&x[“level5”]!=null)
.SelectMany(x=>x[“level5”])
.Where(x=>Convert.ToString(x[“key”])==keyParam)
.选择(x=>x[“值”])
.First().ToString();
有没有比上面写的更好的方法来检查空值?
是否有更好的方法过滤父属性并获取子元素?您可以使用一些技术来简化代码
使用带有通配符表达式的SelectTokens()
向下钻取到最低级别SelectTokens
自动处理空值,因此如果路径上某个节点丢失,它将不会爆炸。您将获得与整个表达式或空枚举(如果没有)匹配的项
创建扩展方法以帮助进行空检查,并在查询中使用这些方法。例如,您可以创建一个方法,该方法将检查JToken
是否为null,如果不是,则检查它是否有与某些条件匹配的子项。e、 g:
public static class JsonExtensions
{
public static bool HasAny(this JToken token, Func<JToken, bool> predicate)
{
return token != null && token.Children().Any(t => predicate(t));
}
}
上述代码向下搜索以选择具有与keyParam
匹配的keyParam
键的level5
的所有子级。然后它沿着链从那里走到level4
,查看filteratr
是否有与filterParam
匹配的子项。(此处需要三个.Parent
,因为包含键属性的对象的父对象是数组,数组的父对象是属性level5
,该属性的父对象是包含filteratr
的对象)如果有任何符合条件的项,我们从这些值返回第一个值
工作演示:谢谢。这很有帮助。有没有一个通用的方法来处理这个问题?就像循环所有元素,直到我找到键并检查是否有任何父项具有FilterATR?那么你是说键可以是任何级别,而不仅仅是级别5
,而filteratr
可以在这上面的任何级别?我的意思是说,如果这是一个结构,我有另一个完全不同的结构,但是我写了一个通用方法,在这里我传入key和filter谓词,并得到传入key的值?将要传递的过滤器将定义层次结构。我仍然不完全清楚您要做什么,但听起来您希望能够在层次结构中向下和向上搜索。如果将JSON解析为一个JObject
,则可以使用substands()
和constances()
扩展方法来帮助实现这一点。也许你在找什么?不,所以我要找的是一个方法,它将第一个参数作为键,即“key1”,第二个作为过滤器,如“level1/level2/level3/level4['filteratr']='filterParam'”,我的方法将基于此进行过滤,并从结果中找到第一个匹配的key1。
string key = jToken.SelectTokens("level1[*].level2[*].level3[*].level4[*].level5[*]")
.Where(x => (string)x["key"] == keyParam &&
x.Parent.Parent.Parent["filterAttr"].HasAny(y => (string)y == filterParam))
.Select(x => (string)x["value"])
.FirstOrDefault();