9

Using the following JSON (from http://jsonpath.com):

{
  "firstName": "John",
  "lastName" : "doe",
  "age"      : 26,
  "address"  : {
    "streetAddress": "naist street",
    "city"         : "Nara",
    "postalCode"   : "630-0192"
  },
  "phoneNumbers": [
    {
      "type"  : "iPhone",
      "number": "0123-4567-8888"
    },
    {
      "type"  : "home",
      "number": "0123-4567-8910"
    }
  ]
}

I would like to get the root object only if firstName is John.

I have tried these inputs and many other similar ones:

  • $.[?($.firstName == 'John')]
  • $.[?($.'firstName' == 'John')]
  • $.[?(@.firstName == 'John')]
  • $[?($.firstName == "John")]

It seems as though filtering is only intended for arrays so this is an unsupported function. Does someone know a way to do this in Json.NET, or confirm that it's not possible and maybe point me to a library which supports the above?

I'm using F# but that's not important because F# is compatible with C#, .NET and NuGet packages.

matt_rule
  • 1,220
  • 1
  • 12
  • 23
  • 2
    Might not be implemented or working. See [Issue #1256: JSONPath scripts not executing correctly for objects](https://github.com/JamesNK/Newtonsoft.Json/issues/1256). Though see [Newtonsoft JSON.Net SelectToken Issue](https://stackoverflow.com/q/39442443/3744182) which found a workaround for a similar issue. Are you actually trying to match the root object, by the way? – dbc Apr 30 '17 at 16:51
  • I was trying to test if a given property was equal to a given string, and if so, return the entire root object. Andy's answer below shows that my approach was wrong. – matt_rule May 02 '17 at 13:07

2 Answers2

6

JSON path is intended to locate data in a JSON object and not to perform some processing or testing on that data. The filter notation is used to identify an item in an array with the purpose of returning that data or some part of it. Having objects in an array means that there may be many properties with the same name that have to be filtered by some other means in order to select a subset of them.
Using filter notation on an object property is not the same thing. There can only be one property in an object with a particular name so stating that name is sufficient to identify it uniquely. You can easily achieve the effect you require by getting $.firstName and then testing separately for the value "John"

Andy Bisson
  • 580
  • 5
  • 19
0

While Andy's answer is correct, there is a way to cheat it. The core of the problem is that the filters work only for arrays, so the solution is to wrap your json object in an array. consider this:

$.arr[?(@.firstName == 'John')]

Let that be your jsonpath expression, you then proceed to do this in your code: (Using python as an example since that is what I am working with, but the same should apply to any language)

tmp_json_obj = json_obj
if jsonpath_str.startswith("$.arr["):
  tmp_json_obj = {"arr": [tmp_json_obj]}
matches = parse(jsonpath_str).find(tmp_json_obj)
if len(matches) > 0:
  print("success, your condition matches the object")
else:
  print("fail, your condition does not match the object")

This implementation makes your other jsonpath queries work normally, and for the situation where you need to conditionally verify the top-level object, you simply add $.arr[ to the expression and make sure you use @ inside the filter instead of $ to refer to your root object

NightRaven
  • 401
  • 3
  • 17