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

时间:2018-07-26 21:21:14

标签: 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);

如果我通过在'data'对象周围添加一个虚拟数组来按摩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);

1 个答案:

答案 0 :(得分:1)

问题是Json.net的JsonPATH过滤器表达式运算符[?()]的实现仅适用于过滤集合(数组)中的对象,而不能过滤其他对象中的对象。在Issue #1256: JSONPath scripts not executing correctly for objects中报告了此限制,Newtonsoft对此进行了回复

  

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

此限制有时会在这里出现,例如What's the correct JsonPath expression to search a JSON root object using Newtonsoft.Json.NET?How to filter a non-array in JsonPath。如果发现对对象内部的对象进行过滤很有用,则可能需要在issue on GitHub上添加注释。

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

string jsonPath = "$.event.data..[?(@.intField == 1)]";

并且,在您的特定情况下,修改后的查询现在可以工作并选择一个对象。演示小提琴here

当然,此修改后的查询还将匹配以下内容:

{
  "event": {
    "data": {
      "extra_added_level_of_nesting": {
        "intField": 1,
        "stringField": "hello"
      }
    }
  }
}

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

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