Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
521 views
in Technique[技术] by (71.8m points)

c# - Json.NET JSONPath query not returning expected results

I'm using Newtonsoft's Json.Net to select nodes from the following json:

{  
   "projects":[  
      {  
         "name":"Project 1",
         "client":{  
            "code":"ABC",
            "name":"Client 1"
         }
      },
      {  
         "name":"Project 2",
         "client":{  
            "code":"DEF",
            "name":"Client 2"
         }
      },
      {  
         "name":"Project 3",
         "client":{  
            "code":"GHI",
            "name":"Client 3"
         }
      }
   ]
}

The following c# snippet

//json is a JObject representation of the json listed above
var clients =  json.SelectTokens("$.projects[*].client");

Yields:

[  
   {  
      "code":"ABC",
      "name":"Client 1"
   },
   {  
      "code":"DEF",
      "name":"Client 2"
   },
   {  
      "code":"GHI",
      "name":"Client 3"
   }
]

Which is cool, now, what I'd like to do is filter by client code, I would think that

$.projects[*].client[?(@.code == 'DEF')]

would work, but I obviously don't understand the syntax well enough. This returns an empty list:

 var test1 =  json.SelectTokens("$.projects[*].client[?(@.code == 'DEF')]").ToList();

And the single token selector returns a null:

  var test2 =  json.SelectToken("$.projects[*].client[?(@.code == 'DEF')]");

I tried a few different configurations on https://jsonpath.curiousconcept.com/ and it seems my query syntax is indeed broken.

Using Flow Communications' JSONPath 0.3.4 implementation (on the above link) I can get the client using

$..[?(@.code == 'DEF')]

however, this syntax does not seem valid for Json.Net (nor the Goessner implementation on the same page).

Anyone see what I'm doing wrong?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Json.NET's JSONPath parser allows the filter (script) expression [?( )] to query for nested properties inside child objects of the candidate array item(s). Thus

var test = json.SelectTokens(@"$.projects[?(@.client.code == 'DEF')].client");

returns, as desired,

[
  {
    "code": "DEF",
    "name": "Client 2"
  }
]

Working .Net fiddle.

Upon experimentation it seems none of the JSONPath implementations at jsonpath.curiousconcept.com support this syntax, however it works correctly at jsonpath.com which uses https://github.com/ashphy/jsonpath-online-evaluator. The JSONPath proposal simply states that () is a script expression, using the underlying script engine which clearly leaves some room for interpretation as to whether and how this "should" work.

The filters used in the question apparently do not work with Json.NET because, as of version 10.0.3, it only officially supports applying filters to array items and not directly to objects -- see Issue #1256: JSONPath scripts not executing correctly for objects for a discussion. (Though sometimes cunning workarounds can be found, for instance in this answer.) Using nested properties inside filters, however, seems to be intended to work (and does work).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...