-Added support for root object in JSONPath filters
This commit is contained in:
@@ -949,5 +949,57 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
result = a.SelectTokens("$.[?(@.value)]").ToList();
|
||||
Assert.AreEqual(4, result.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RootInFilter()
|
||||
{
|
||||
string json = @"[
|
||||
{
|
||||
""store"" : {
|
||||
""book"" : [
|
||||
{
|
||||
""category"" : ""reference"",
|
||||
""author"" : ""Nigel Rees"",
|
||||
""title"" : ""Sayings of the Century"",
|
||||
""price"" : 8.95
|
||||
},
|
||||
{
|
||||
""category"" : ""fiction"",
|
||||
""author"" : ""Evelyn Waugh"",
|
||||
""title"" : ""Sword of Honour"",
|
||||
""price"" : 12.99
|
||||
},
|
||||
{
|
||||
""category"" : ""fiction"",
|
||||
""author"" : ""Herman Melville"",
|
||||
""title"" : ""Moby Dick"",
|
||||
""isbn"" : ""0-553-21311-3"",
|
||||
""price"" : 8.99
|
||||
},
|
||||
{
|
||||
""category"" : ""fiction"",
|
||||
""author"" : ""J. R. R. Tolkien"",
|
||||
""title"" : ""The Lord of the Rings"",
|
||||
""isbn"" : ""0-395-19395-8"",
|
||||
""price"" : 22.99
|
||||
}
|
||||
],
|
||||
""bicycle"" : {
|
||||
""color"" : ""red"",
|
||||
""price"" : 19.95
|
||||
}
|
||||
},
|
||||
""expensive"" : 10
|
||||
}
|
||||
]";
|
||||
|
||||
JArray a = JArray.Parse(json);
|
||||
|
||||
List<JToken> result = a.SelectTokens("$.[?($.store.bicycle.price < 20)]").ToList();
|
||||
Assert.AreEqual(1, result.Count);
|
||||
|
||||
result = a.SelectTokens("$.[?($.store.bicycle.price < 10)]").ToList();
|
||||
Assert.AreEqual(0, result.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,6 +419,16 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual(QueryOperator.Exists, orExpression.Expressions[1].Operator);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FilterWithRoot()
|
||||
{
|
||||
JPath path = new JPath("[?($.name>=12.1)]");
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
Assert.AreEqual(2, expressions.Path.Count);
|
||||
Assert.IsInstanceOf(typeof(RootFilter), expressions.Path[0]);
|
||||
Assert.IsInstanceOf(typeof(FieldFilter), expressions.Path[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BadOr1()
|
||||
{
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{ "LastName", "LastName!" }
|
||||
};
|
||||
|
||||
Assert.IsTrue(compositeExpression.IsMatch(o1));
|
||||
Assert.IsTrue(compositeExpression.IsMatch(o1, o1));
|
||||
|
||||
JObject o2 = new JObject
|
||||
{
|
||||
@@ -94,14 +94,14 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{ "FirstName", "FirstName!" }
|
||||
};
|
||||
|
||||
Assert.IsFalse(compositeExpression.IsMatch(o2));
|
||||
Assert.IsFalse(compositeExpression.IsMatch(o2, o2));
|
||||
|
||||
JObject o3 = new JObject
|
||||
{
|
||||
{ "Title", "Title!" }
|
||||
};
|
||||
|
||||
Assert.IsFalse(compositeExpression.IsMatch(o3));
|
||||
Assert.IsFalse(compositeExpression.IsMatch(o3, o3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -144,7 +144,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{ "LastName", "LastName!" }
|
||||
};
|
||||
|
||||
Assert.IsTrue(compositeExpression.IsMatch(o1));
|
||||
Assert.IsTrue(compositeExpression.IsMatch(o1, o1));
|
||||
|
||||
JObject o2 = new JObject
|
||||
{
|
||||
@@ -152,14 +152,14 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{ "FirstName", "FirstName!" }
|
||||
};
|
||||
|
||||
Assert.IsTrue(compositeExpression.IsMatch(o2));
|
||||
Assert.IsTrue(compositeExpression.IsMatch(o2, o2));
|
||||
|
||||
JObject o3 = new JObject
|
||||
{
|
||||
{ "Title", "Title!" }
|
||||
};
|
||||
|
||||
Assert.IsFalse(compositeExpression.IsMatch(o3));
|
||||
Assert.IsFalse(compositeExpression.IsMatch(o3, o3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -175,10 +175,10 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
}
|
||||
};
|
||||
|
||||
Assert.IsTrue(e1.IsMatch(new JArray(1, 2, 3, 4, 5)));
|
||||
Assert.IsTrue(e1.IsMatch(new JArray(2, 3, 4, 5)));
|
||||
Assert.IsFalse(e1.IsMatch(new JArray(3, 4, 5)));
|
||||
Assert.IsFalse(e1.IsMatch(new JArray(4, 5)));
|
||||
Assert.IsTrue(e1.IsMatch(null, new JArray(1, 2, 3, 4, 5)));
|
||||
Assert.IsTrue(e1.IsMatch(null, new JArray(2, 3, 4, 5)));
|
||||
Assert.IsFalse(e1.IsMatch(null, new JArray(3, 4, 5)));
|
||||
Assert.IsFalse(e1.IsMatch(null, new JArray(4, 5)));
|
||||
|
||||
BooleanQueryExpression e2 = new BooleanQueryExpression
|
||||
{
|
||||
@@ -190,10 +190,10 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
}
|
||||
};
|
||||
|
||||
Assert.IsTrue(e2.IsMatch(new JArray(1, 2, 3, 4, 5)));
|
||||
Assert.IsTrue(e2.IsMatch(new JArray(2, 3, 4, 5)));
|
||||
Assert.IsTrue(e2.IsMatch(new JArray(3, 4, 5)));
|
||||
Assert.IsFalse(e2.IsMatch(new JArray(4, 5)));
|
||||
Assert.IsTrue(e2.IsMatch(null, new JArray(1, 2, 3, 4, 5)));
|
||||
Assert.IsTrue(e2.IsMatch(null, new JArray(2, 3, 4, 5)));
|
||||
Assert.IsTrue(e2.IsMatch(null, new JArray(3, 4, 5)));
|
||||
Assert.IsFalse(e2.IsMatch(null, new JArray(4, 5)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2305,7 +2305,7 @@ namespace Newtonsoft.Json.Linq
|
||||
JPath p = new JPath(path);
|
||||
|
||||
JToken token = null;
|
||||
foreach (JToken t in p.Evaluate(this, errorWhenNoMatch))
|
||||
foreach (JToken t in p.Evaluate(this, this, errorWhenNoMatch))
|
||||
{
|
||||
if (token != null)
|
||||
{
|
||||
@@ -2341,7 +2341,7 @@ namespace Newtonsoft.Json.Linq
|
||||
public IEnumerable<JToken> SelectTokens(string path, bool errorWhenNoMatch)
|
||||
{
|
||||
JPath p = new JPath(path);
|
||||
return p.Evaluate(this, errorWhenNoMatch);
|
||||
return p.Evaluate(this, this, errorWhenNoMatch);
|
||||
}
|
||||
|
||||
#if !(NET35 || NET20 || PORTABLE40)
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
public int? Index { get; set; }
|
||||
|
||||
public override IEnumerable<JToken> ExecuteFilter(IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
{
|
||||
foreach (JToken t in current)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
public List<int> Indexes { get; set; }
|
||||
|
||||
public override IEnumerable<JToken> ExecuteFilter(IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
{
|
||||
foreach (JToken t in current)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
public int? End { get; set; }
|
||||
public int? Step { get; set; }
|
||||
|
||||
public override IEnumerable<JToken> ExecuteFilter(IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
{
|
||||
if (Step == 0)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public override IEnumerable<JToken> ExecuteFilter(IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
{
|
||||
foreach (JToken t in current)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
public List<string> Names { get; set; }
|
||||
|
||||
public override IEnumerable<JToken> ExecuteFilter(IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
{
|
||||
foreach (JToken t in current)
|
||||
{
|
||||
|
||||
@@ -429,15 +429,19 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
EatWhitespace();
|
||||
|
||||
if (_expression[_currentIndex] != '@')
|
||||
List<PathFilter> expressionPath = new List<PathFilter>();
|
||||
|
||||
if (_expression[_currentIndex] == '$')
|
||||
{
|
||||
expressionPath.Add(new RootFilter());
|
||||
}
|
||||
else if (_expression[_currentIndex] != '@')
|
||||
{
|
||||
throw new JsonException("Unexpected character while parsing path query: " + _expression[_currentIndex]);
|
||||
}
|
||||
|
||||
_currentIndex++;
|
||||
|
||||
List<PathFilter> expressionPath = new List<PathFilter>();
|
||||
|
||||
if (ParsePath(expressionPath, _currentIndex, true))
|
||||
{
|
||||
throw new JsonException("Path ended with open query.");
|
||||
@@ -758,17 +762,17 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
}
|
||||
}
|
||||
|
||||
internal IEnumerable<JToken> Evaluate(JToken t, bool errorWhenNoMatch)
|
||||
internal IEnumerable<JToken> Evaluate(JToken root, JToken t, bool errorWhenNoMatch)
|
||||
{
|
||||
return Evaluate(Filters, t, errorWhenNoMatch);
|
||||
return Evaluate(Filters, root, t, errorWhenNoMatch);
|
||||
}
|
||||
|
||||
internal static IEnumerable<JToken> Evaluate(List<PathFilter> filters, JToken t, bool errorWhenNoMatch)
|
||||
internal static IEnumerable<JToken> Evaluate(List<PathFilter> filters, JToken root, JToken t, bool errorWhenNoMatch)
|
||||
{
|
||||
IEnumerable<JToken> current = new[] { t };
|
||||
foreach (PathFilter filter in filters)
|
||||
{
|
||||
current = filter.ExecuteFilter(current, errorWhenNoMatch);
|
||||
current = filter.ExecuteFilter(root, current, errorWhenNoMatch);
|
||||
}
|
||||
|
||||
return current;
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
internal abstract class PathFilter
|
||||
{
|
||||
public abstract IEnumerable<JToken> ExecuteFilter(IEnumerable<JToken> current, bool errorWhenNoMatch);
|
||||
public abstract IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, bool errorWhenNoMatch);
|
||||
|
||||
protected static JToken GetTokenIndex(JToken t, bool errorWhenNoMatch, int index)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
public QueryOperator Operator { get; set; }
|
||||
|
||||
public abstract bool IsMatch(JToken t);
|
||||
public abstract bool IsMatch(JToken root, JToken t);
|
||||
}
|
||||
|
||||
internal class CompositeExpression : QueryExpression
|
||||
@@ -36,14 +36,14 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
Expressions = new List<QueryExpression>();
|
||||
}
|
||||
|
||||
public override bool IsMatch(JToken t)
|
||||
public override bool IsMatch(JToken root, JToken t)
|
||||
{
|
||||
switch (Operator)
|
||||
{
|
||||
case QueryOperator.And:
|
||||
foreach (QueryExpression e in Expressions)
|
||||
{
|
||||
if (!e.IsMatch(t))
|
||||
if (!e.IsMatch(root, t))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
case QueryOperator.Or:
|
||||
foreach (QueryExpression e in Expressions)
|
||||
{
|
||||
if (e.IsMatch(t))
|
||||
if (e.IsMatch(root, t))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -69,9 +69,9 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
public List<PathFilter> Path { get; set; }
|
||||
public JValue Value { get; set; }
|
||||
|
||||
public override bool IsMatch(JToken t)
|
||||
public override bool IsMatch(JToken root, JToken t)
|
||||
{
|
||||
IEnumerable<JToken> pathResult = JPath.Evaluate(Path, t, false);
|
||||
IEnumerable<JToken> pathResult = JPath.Evaluate(Path, root, t, false);
|
||||
|
||||
foreach (JToken r in pathResult)
|
||||
{
|
||||
|
||||
@@ -7,13 +7,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
public QueryExpression Expression { get; set; }
|
||||
|
||||
public override IEnumerable<JToken> ExecuteFilter(IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
{
|
||||
foreach (JToken t in current)
|
||||
{
|
||||
foreach (JToken v in t)
|
||||
{
|
||||
if (Expression.IsMatch(v))
|
||||
if (Expression.IsMatch(root, v))
|
||||
{
|
||||
yield return v;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
internal class RootFilter : PathFilter
|
||||
{
|
||||
public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
{
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,17 +6,17 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public override IEnumerable<JToken> ExecuteFilter(IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, bool errorWhenNoMatch)
|
||||
{
|
||||
foreach (JToken root in current)
|
||||
foreach (JToken c in current)
|
||||
{
|
||||
if (Name == null)
|
||||
{
|
||||
yield return root;
|
||||
yield return c;
|
||||
}
|
||||
|
||||
JToken value = root;
|
||||
JToken container = root;
|
||||
JToken value = c;
|
||||
JToken container = c;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -26,12 +26,12 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
}
|
||||
else
|
||||
{
|
||||
while (value != null && value != root && value == value.Parent.Last)
|
||||
while (value != null && value != c && value == value.Parent.Last)
|
||||
{
|
||||
value = value.Parent;
|
||||
}
|
||||
|
||||
if (value == null || value == root)
|
||||
if (value == null || value == c)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
<Compile Include="Linq\JsonPath\PathFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryExpression.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\RootFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\ScanFilter.cs" />
|
||||
<Compile Include="Linq\MergeArrayHandling.cs" />
|
||||
<Compile Include="Linq\MergeNullValueHandling.cs" />
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
<Compile Include="Linq\JsonPath\PathFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryExpression.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\RootFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\ScanFilter.cs" />
|
||||
<Compile Include="Linq\MergeArrayHandling.cs" />
|
||||
<Compile Include="Linq\MergeNullValueHandling.cs" />
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
<Compile Include="Linq\JsonPath\PathFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryExpression.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\RootFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\ScanFilter.cs" />
|
||||
<Compile Include="Linq\MergeArrayHandling.cs" />
|
||||
<Compile Include="Linq\MergeNullValueHandling.cs" />
|
||||
|
||||
@@ -128,6 +128,7 @@
|
||||
<Compile Include="Linq\JsonPath\PathFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryExpression.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\RootFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\ScanFilter.cs" />
|
||||
<Compile Include="Linq\JToken.cs" />
|
||||
<Compile Include="Linq\JTokenEqualityComparer.cs" />
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
<Compile Include="Linq\JsonPath\PathFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryExpression.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\RootFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\ScanFilter.cs" />
|
||||
<Compile Include="Linq\JToken.cs" />
|
||||
<Compile Include="Linq\JTokenEqualityComparer.cs" />
|
||||
|
||||
@@ -131,6 +131,7 @@
|
||||
<Compile Include="Linq\JsonPath\PathFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryExpression.cs" />
|
||||
<Compile Include="Linq\JsonPath\QueryFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\RootFilter.cs" />
|
||||
<Compile Include="Linq\JsonPath\ScanFilter.cs" />
|
||||
<Compile Include="Linq\JToken.cs" />
|
||||
<Compile Include="Linq\JTokenEqualityComparer.cs" />
|
||||
|
||||
Reference in New Issue
Block a user