json 路径表达式在没有数组的情况下不起作用

Kau*_*ric 3 c# json.net jsonpath

我正在尝试实现一个看似简单的 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);
Run Code Online (Sandbox Code Playgroud)

如果我通过在“数据”对象周围添加虚拟数组来处理 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);
Run Code Online (Sandbox Code Playgroud)

dbc*_*dbc 6

问题是 Json.NET 的 JsonPATH 过滤表达式运算符的实现[?()]仅适用于过滤集合(数组)内的对象,而不适用于其他对象内的对象。此限制在问题#1256中报告:JSONPath脚本无法正确执行对象,Newtonsoft回复说,

我对此不太确定。JSONPath 中没有任何内容表明过滤器应应用于对象。
JamesNK于 2017 年 3 月 24 日发表评论

这种限制时常出现,例如使用 Newtonsoft.Json.NET 搜索 JSON 根对象的正确 JsonPath 表达式是什么?如何过滤 JsonPath 中的非数组。如果您发现对对象内部的对象进行过滤很有用,您可能需要在 GitHub 上的问题中添加评论。

有时可以完成此工作的解决方法是在包含对象属性名称和过滤表达式运算符之间添加递归下降运算符..,如下所示:

string jsonPath = "$.event.data..[?(@.intField == 1)]";
Run Code Online (Sandbox Code Playgroud)

而且,在您的具体情况下,修改后的查询现在可以运行并选择一个对象。演示小提琴在这里

当然,这个修改后的查询也将匹配如下内容:

{
  "event": {
    "data": {
      "extra_added_level_of_nesting": {
        "intField": 1,
        "stringField": "hello"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

(此处小提琴#2 )因此解决方法可能不足以满足您的需求。

该解决方法之所以成功,是因为 Json.NET 显然将递归下降运算符返回的结果视为一个集合,因此可以对其应用过滤表达式运算符。