You can use JToken.SelectTokens()
to run nested queries on LINQ to JSON objects:
var valueQuery = globalEventStream
.Select(e => JObject.Parse(e.EventArgs.Data))
.Where(o => o.SelectTokens("Key1.key2").Any());
Sample fiddle.
The specification for JSONPath is here and supports the following query syntax:
XPath JSONPath Description
/ $ the root object/element
. @ the current object/element
/ . or [] child operator
.. n/a parent operator
// .. recursive descent. JSONPath borrows this syntax from E4X.
* * wildcard. All objects/elements regardless their names.
@ n/a attribute access. JSON structures don't have attributes.
[] [] subscript operator. XPath uses it to iterate over element collections and for predicates. In Javascript and JSON it is the native array operator.
| [,] Union operator in XPath results in a combination of node sets. JSONPath allows alternate names or array indices as a set.
n/a [start:end:step] array slice operator borrowed from ES4.
[] ?() applies a filter (script) expression.
n/a () script expression, using the underlying script engine.
() n/a grouping in Xpath
E.g., for the following JSON:
{ "Key1" : [{"NoKey2":"value"}, {"key2":"value"}], "key3" : "other values" }
You could use the wildcard operator *
to test for the presence of any item in the array with a "key2"
property as follows:
var valueQuery = globalEventStream
.Select(e => JObject.Parse(e.EventArgs.Data))
.Where(o => o.SelectTokens("Key1[*].key2").Any());
Here Enumerable.Any()
tests to see whether the SelectTokens()
query found more than zero results -- i.e., is there at least one entry in the "Key1"
array with a "key2"
property. It's more efficient than doing Enumerable.Count()
since it stops the evaluation as soon as one item is returned.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…