我正在尝试实现一个看似简单的 JSON 路径过滤器,但未能使其正常工作。想知道其他对 Json.NET 的 JSON 路径实现有更多经验的人是否对下一步有想法。
这个场景失败了,但我认为应该可行?
var jsonText = @"{
'event': {
'data': {
'intField': 1,
'stringField': 'hello'
}
}
}";
JObject json = JsonConvert.DeserializeObject<JObject>(jsonText);
string jsonPath = "$.event.data[?(@.intField == 1)]";
IList<JToken> output = json.SelectTokens(jsonPath).ToList();
// this check fails
Assert.IsTrue(output.ToList().Count > 0);
如果我通过在“数据”对象周围添加虚拟数组来处理 JSON 有效负载,那么我就可以让查询正常工作。但是,我宁愿不处理 JSON 有效负载。
var jsonText = @"{
'event': {
'data': [{
'intField': 1,
'stringField': 'hello'
}]
}
}";
JObject json = JsonConvert.DeserializeObject<JObject>(jsonText);
string jsonPath = "$.event.data[?(@.intField == 1)]";
IList<JToken> output = json.SelectTokens(jsonPath).ToList();
// now this works
Assert.IsTrue(output.ToList().Count > 0);
问题是Json.NET的JsonPATH过滤表达式运算符
[?()]
的实现仅适用于过滤集合(数组)内的对象——不适用于其他对象内的对象。此限制在 Issue #1256:JSONPath 脚本无法正确执行对象中报告,Newtonsoft 对此回复称,
我对此不太确定。 JSONPath 中没有任何内容表明过滤器应应用于对象。
JamesNK于2017年3月24日发表评论
此限制有时会出现,例如使用 Newtonsoft.Json.NET 搜索 JSON 根对象的正确 JsonPath 表达式是什么? 或 如何过滤 JsonPath 中的非数组。如果您发现过滤对象内的对象很有用,您可能需要向 GitHub 上的 issue 添加评论。
有时可以完成这项工作的解决方法是在包含对象属性名称和过滤表达式运算符之间添加递归下降运算符..
,如下所示:
string jsonPath = "$.event.data..[?(@.intField == 1)]";
并且,在您的具体情况下,修改后的查询现在可以工作并选择一个对象。演示小提琴这里.
当然,这个修改后的查询也会匹配如下内容:
{
"event": {
"data": {
"extra_added_level_of_nesting": {
"intField": 1,
"stringField": "hello"
}
}
}
}
(小提琴#2解决方法成功了,因为显然,Json.NET 认为递归下降运算符返回的结果是一个集合,因此可以对其应用过滤表达式运算符。
{"x":{"a":1, "b":2}}
和给定的 JSONPath 表达式:
$.x.*
- 结果是
[1, 2]
- 而不是某些人可能期望的
[{"a":1}, {"b":2}]
。这就是 JSONPath 的工作原理。映射成员的匹配解析为该成员的值。类似地,对于 JSONPath 表达式,
$.x[?@]
结果是
[1, 2]
- 只是
x
的成员值,而不是
[{"a":1}, {"b":2}]
。因此您无法访问
@.a
。类似地,对于 JSONPath 表达式
$[?@]
- 结果是
[{"a":1, "b":2}]
- 只是
x
的值,而不是
["x":{"a":1, "b":2}]