JamesNK / Newtonsoft.Json

Json.NET is a popular high-performance JSON framework for .NET
https://www.newtonsoft.com/json
MIT License
10.81k stars 3.26k forks source link

JSONPath issue with filter expressions #2068

Open smourier opened 5 years ago

smourier commented 5 years ago

Here is a sample C# code

        var s = @"
        {
            length: {
                '@units' : 'minutes',
                '#text' : '105'
            }
        }";

        var obj = JObject.Parse(s);
        foreach (var tok in obj.SelectTokens("length"))
        {
            Console.WriteLine(tok); // display the whole length object
        }

        foreach (var tok in obj.SelectTokens("length[?(true)]"))
        {
            Console.WriteLine(tok); // display a list of length's children tokens
        }

Expected behavior

I expect both SelectTokens calls to behave the same way.

Actual behavior

First call is ok, but second one selects children tokens of the 'length' object, instead of the 'length' object itself.

This is just an example, but my ultimate goal is to be able to filter on some properties, for example a path like length[?(@units=='minutes')], maybe there is another way to do this? It looks like the filter syntax only supports array objects.

Thraka commented 5 years ago

I just ran into this too. It was driving me crazy because I thought I was getting syntax wrong, as I'm new to jsonpath stuff. But after some posts elsewhere and some online testing I found my syntax was correct and it just seems the jsonpath stuff in the library isn't as capable as I needed.

I'm trying to do:

{
  "Issue": {
    "Id": 50170,
    "NodeId": "MD=",
    "Url": "https://api.github.com",
    "HtmlUrl": "https://github.com",
    "CommentsUrl": "https://api.github.com",
    "EventsUrl": "https://api.github.com",
    "Number": 105,
    "State": {
      "StringValue": "open",
      "Value": 0
    }
  }
}

With query

$.Issue.State[?(@.Value == 0)]

But it fails. http://jsonpath.herokuapp.com/ seems like a good place to test.

smourier commented 5 years ago

IMHO, JSONPath (I believe the official definition is here: https://goessner.net/articles/JsonPath/) is itself a half-baked spec.

From what I understand [] is the "child" operator so it always gives back children. And this operator contains an optional filter. So that may be perfectly normal (but noone seems interested anyway ... ).

Thraka commented 5 years ago

I think I found a better way. https://www.nuget.org/packages/JmesPath.Net and playing with that query language: http://jmespath.org (which also contains a testing section to play around with it)

Simply do this where obj is a JObject or JToken, something that you can get the string json back out of.

var path = new DevLab.JmesPath.JmesPath();
var result = path.Transform(obj.Root.ToString(), "Issue.State.StringValue == 'open'");

It's a .NET Standard lib with little dependencies.