2

I am creating list of JObject like below. I would like to search the collection using query expression. In the sample code below I am using Jsonpath query to find all position object which is of type Buy (enum Buy has int value of 1 )

List<JObject> list = new List<JObject>();
list.Add(JObject.FromObject(new Position() { PositionType = PositionType.Buy, Investment = new Investment() { InvestmentCode = "AAPL" } }));
list.Add(JObject.FromObject(new Position() { PositionType = PositionType.Sell, Investment = new Investment() { InvestmentCode = "AAPL" } }));

var x = list.Find(j =>
{
    JToken token =  j.SelectToken("$[?(@.PositionType == 1)]");
    return token != null;
});

The SelectToken method returns null within the predicate. I am not sure if I am using a right method. Is there a way a predicate can be evaluated on the object?

  • `var x = list.Find(j => j.SelectToken("$[?(@.PositionType == 1)]"));` that is what the line should be, but, you probably should do something more like `list.Where(j => j["PositionType"] != null).First(j => j["PositionType"] == 1)` – Callum Linington Aug 17 '16 at 15:26
  • If you have it as a .NET type already, why not just do a LINQ query on the collection directly? Why convert it to a JObject first? – EJoshuaS - Stand with Ukraine Aug 17 '16 at 15:39
  • I provided above sample for an example. My intention is to build a dynamic Json object store and have caller provide filter using json path. The library would have no knowledge of the type. – Chirag Shah Aug 17 '16 at 15:53

1 Answers1

1

It's not well explained by the SelectTokens() documentation or the JSONPath standard, but the [?(script)] operator is arguably defined to be for conditional selection of child objects. This is because the [?()] operator is actually a combination of the script operator nested inside the child/subscript operator. From the standard:

Here is a complete overview and a side by side comparison of the JSONPath syntax elements with its XPath counterparts.

XPath    JSONPath    Description 
/        . or []     child operator 
[]       []          subscript operator. XPath uses it to iterate over element collections and for predicates. In Javascript and JSON it is the native array operator. 
[]       ?()         applies a filter (script) expression. 
n/a      ()          script expression, using the underlying script engine. 

The only examples the standard shows of the [?()] operator is in matching properties of objects inside arrays, and returning those objects.

Thus if I do SelectTokens() on [{"PositionType": 1}] using "$[?(@.PositionType == 1)]" then one object is returned, but doing it on {"PositionType": 1} (as you are trying to do inside your Find() predicate) returns nothing.

Json.NET is not entirely idiosyncratic in its interpretation of the standard. Here are the results of trying to match {"PositionType": 1} against "$[?(@.PositionType == 1)]" and $..[?(@.PositionType == 1)] using various JSONPath parsers:

You could report an issue about Json.NET's behavior, but given the inconsistency between implementations it might not get addressed. The JSONPath standard simply may not be well-defined and stable enough for your needs as compared to XPath at this point.

See also Newtonsoft JSON SelectToken to get data from multiple parts of JSON document? and How to select JToken based on multiple name candidates in JSONPath?.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • 1
    Jayway's webapp doesn't use an up-to-date Gatling JsonPath version (0.6.4, released more than one year ago). I tested with latest 0.6.7 and both expressions match properly. – Stephane Landelle Aug 17 '16 at 22:50