-Added support for any combination of paths and values in JSONPath filter expressions
This commit is contained in:
@@ -723,6 +723,21 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("hi", 3)), t[1]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LesserQuery_ValueFirst()
|
||||
{
|
||||
JArray a = new JArray(
|
||||
new JObject(new JProperty("hi", 1)),
|
||||
new JObject(new JProperty("hi", 2)),
|
||||
new JObject(new JProperty("hi", 3)));
|
||||
|
||||
IList<JToken> t = a.SelectTokens("[ ?( 1 < @.hi ) ]").ToList();
|
||||
Assert.IsNotNull(t);
|
||||
Assert.AreEqual(2, t.Count);
|
||||
Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("hi", 2)), t[0]));
|
||||
Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("hi", 3)), t[1]));
|
||||
}
|
||||
|
||||
#if !(PORTABLE || DNXCORE50 || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_1
|
||||
[Test]
|
||||
public void GreaterQueryBigInteger()
|
||||
@@ -811,6 +826,79 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual(1L, v.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MultiplePaths()
|
||||
{
|
||||
JArray a = JArray.Parse(@"[
|
||||
{
|
||||
""price"": 199,
|
||||
""max_price"": 200
|
||||
},
|
||||
{
|
||||
""price"": 200,
|
||||
""max_price"": 200
|
||||
},
|
||||
{
|
||||
""price"": 201,
|
||||
""max_price"": 200
|
||||
}
|
||||
]");
|
||||
|
||||
var results = a.SelectTokens("[?(@.price > @.max_price)]").ToList();
|
||||
Assert.AreEqual(1, results.Count);
|
||||
Assert.AreEqual(a[2], results[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Exists_True()
|
||||
{
|
||||
JArray a = JArray.Parse(@"[
|
||||
{
|
||||
""price"": 199,
|
||||
""max_price"": 200
|
||||
},
|
||||
{
|
||||
""price"": 200,
|
||||
""max_price"": 200
|
||||
},
|
||||
{
|
||||
""price"": 201,
|
||||
""max_price"": 200
|
||||
}
|
||||
]");
|
||||
|
||||
var results = a.SelectTokens("[?(true)]").ToList();
|
||||
Assert.AreEqual(3, results.Count);
|
||||
Assert.AreEqual(a[0], results[0]);
|
||||
Assert.AreEqual(a[1], results[1]);
|
||||
Assert.AreEqual(a[2], results[2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Exists_Null()
|
||||
{
|
||||
JArray a = JArray.Parse(@"[
|
||||
{
|
||||
""price"": 199,
|
||||
""max_price"": 200
|
||||
},
|
||||
{
|
||||
""price"": 200,
|
||||
""max_price"": 200
|
||||
},
|
||||
{
|
||||
""price"": 201,
|
||||
""max_price"": 200
|
||||
}
|
||||
]");
|
||||
|
||||
var results = a.SelectTokens("[?(true)]").ToList();
|
||||
Assert.AreEqual(3, results.Count);
|
||||
Assert.AreEqual(a[0], results[0]);
|
||||
Assert.AreEqual(a[1], results[1]);
|
||||
Assert.AreEqual(a[2], results[2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WildcardWithProperty()
|
||||
{
|
||||
|
||||
@@ -46,6 +46,31 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
[TestFixture]
|
||||
public class JPathParseTests : TestFixtureBase
|
||||
{
|
||||
[Test]
|
||||
public void BooleanQuery_TwoValues()
|
||||
{
|
||||
JPath path = new JPath("[?(1 > 2)]");
|
||||
Assert.AreEqual(1, path.Filters.Count);
|
||||
BooleanQueryExpression booleanExpression = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
Assert.AreEqual(new JValue(1), booleanExpression.Left);
|
||||
Assert.AreEqual(new JValue(1), booleanExpression.Right);
|
||||
Assert.AreEqual(QueryOperator.GreaterThan, booleanExpression.Operator);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BooleanQuery_TwoPaths()
|
||||
{
|
||||
JPath path = new JPath("[?(@.price > @.max_price)]");
|
||||
Assert.AreEqual(1, path.Filters.Count);
|
||||
BooleanQueryExpression booleanExpression = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
List<PathFilter> leftPaths = (List<PathFilter>)booleanExpression.Left;
|
||||
List<PathFilter> rightPaths = (List<PathFilter>)booleanExpression.Right;
|
||||
|
||||
Assert.AreEqual("price", ((FieldFilter)leftPaths[0]).Name);
|
||||
Assert.AreEqual("max_price", ((FieldFilter)rightPaths[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.GreaterThan, booleanExpression.Operator);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SingleProperty()
|
||||
{
|
||||
@@ -228,8 +253,9 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
|
||||
Assert.AreEqual(QueryOperator.Exists, expressions.Operator);
|
||||
Assert.AreEqual(1, expressions.Path.Count);
|
||||
Assert.AreEqual("name", ((ScanFilter)expressions.Path[0]).Name);
|
||||
List<PathFilter> paths = (List<PathFilter>)expressions.Left;
|
||||
Assert.AreEqual(1, paths.Count);
|
||||
Assert.AreEqual("name", ((ScanFilter)paths[0]).Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -240,7 +266,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
|
||||
Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
|
||||
Assert.AreEqual("hi", (string)expressions.Value);
|
||||
Assert.AreEqual("hi", (string)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -251,7 +277,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
|
||||
Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
|
||||
Assert.AreEqual("h'i", (string)expressions.Value);
|
||||
Assert.AreEqual("h'i", (string)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -262,7 +288,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
|
||||
Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
|
||||
Assert.AreEqual("h\\i", (string)expressions.Value);
|
||||
Assert.AreEqual("h\\i", (string)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -279,7 +305,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
|
||||
Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
|
||||
Assert.AreEqual(false, (bool)expressions.Value);
|
||||
Assert.AreEqual(false, (bool)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -290,7 +316,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
|
||||
Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
|
||||
Assert.AreEqual(true, (bool)expressions.Value);
|
||||
Assert.AreEqual(true, (bool)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -301,7 +327,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
|
||||
Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
|
||||
Assert.AreEqual(null, expressions.Value.Value);
|
||||
Assert.AreEqual(null, ((JValue)expressions.Right).Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -309,7 +335,8 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{
|
||||
JPath path = new JPath("[?(@..name<>null)]");
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
Assert.AreEqual("name", ((ScanFilter)expressions.Path[0]).Name);
|
||||
List<PathFilter> paths = (List<PathFilter>)expressions.Left;
|
||||
Assert.AreEqual("name", ((ScanFilter)paths[0]).Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -365,7 +392,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{
|
||||
JPath path = new JPath("[?(@.name>=12)]");
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
Assert.AreEqual(12, (int)expressions.Value);
|
||||
Assert.AreEqual(12, (int)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -373,7 +400,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{
|
||||
JPath path = new JPath("[?(@.name>=-12)]");
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
Assert.AreEqual(-12, (int)expressions.Value);
|
||||
Assert.AreEqual(-12, (int)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -381,7 +408,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{
|
||||
JPath path = new JPath("[?(@.name>=12.1)]");
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
Assert.AreEqual(12.1d, (double)expressions.Value);
|
||||
Assert.AreEqual(12.1d, (double)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -391,10 +418,16 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
CompositeExpression expressions = (CompositeExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
Assert.AreEqual(QueryOperator.And, expressions.Operator);
|
||||
Assert.AreEqual(2, expressions.Expressions.Count);
|
||||
Assert.AreEqual("name", ((FieldFilter)((BooleanQueryExpression)expressions.Expressions[0]).Path[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, expressions.Expressions[0].Operator);
|
||||
Assert.AreEqual("title", ((FieldFilter)((BooleanQueryExpression)expressions.Expressions[1]).Path[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, expressions.Expressions[1].Operator);
|
||||
|
||||
var first = (BooleanQueryExpression)expressions.Expressions[0];
|
||||
var firstPaths = (List<PathFilter>)first.Left;
|
||||
Assert.AreEqual("name", ((FieldFilter)firstPaths[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, first.Operator);
|
||||
|
||||
var second = (BooleanQueryExpression)expressions.Expressions[1];
|
||||
var secondPaths = (List<PathFilter>)second.Left;
|
||||
Assert.AreEqual("title", ((FieldFilter)secondPaths[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, second.Operator);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -404,15 +437,24 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
CompositeExpression andExpression = (CompositeExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
Assert.AreEqual(QueryOperator.And, andExpression.Operator);
|
||||
Assert.AreEqual(2, andExpression.Expressions.Count);
|
||||
Assert.AreEqual("name", ((FieldFilter)((BooleanQueryExpression)andExpression.Expressions[0]).Path[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, andExpression.Expressions[0].Operator);
|
||||
|
||||
var first = (BooleanQueryExpression)andExpression.Expressions[0];
|
||||
var firstPaths = (List<PathFilter>)first.Left;
|
||||
Assert.AreEqual("name", ((FieldFilter)firstPaths[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, first.Operator);
|
||||
|
||||
CompositeExpression orExpression = (CompositeExpression)andExpression.Expressions[1];
|
||||
Assert.AreEqual(2, orExpression.Expressions.Count);
|
||||
Assert.AreEqual("title", ((FieldFilter)((BooleanQueryExpression)orExpression.Expressions[0]).Path[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, orExpression.Expressions[0].Operator);
|
||||
Assert.AreEqual("pie", ((FieldFilter)((BooleanQueryExpression)orExpression.Expressions[1]).Path[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, orExpression.Expressions[1].Operator);
|
||||
|
||||
var orFirst = (BooleanQueryExpression)orExpression.Expressions[0];
|
||||
var orFirstPaths = (List<PathFilter>)orFirst.Left;
|
||||
Assert.AreEqual("title", ((FieldFilter)orFirstPaths[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, orFirst.Operator);
|
||||
|
||||
var orSecond = (BooleanQueryExpression)orExpression.Expressions[1];
|
||||
var orSecondPaths = (List<PathFilter>)orSecond.Left;
|
||||
Assert.AreEqual("pie", ((FieldFilter)orSecondPaths[0]).Name);
|
||||
Assert.AreEqual(QueryOperator.Exists, orSecond.Operator);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -420,9 +462,10 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{
|
||||
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]);
|
||||
List<PathFilter> paths = (List<PathFilter>)expressions.Left;
|
||||
Assert.AreEqual(2, paths.Count);
|
||||
Assert.IsInstanceOf(typeof(RootFilter), paths[0]);
|
||||
Assert.IsInstanceOf(typeof(FieldFilter), paths[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -478,7 +521,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
{
|
||||
JPath path = new JPath("[?(@.name>=5.56789e+0)]");
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
|
||||
Assert.AreEqual(5.56789e+0, (double)expressions.Value);
|
||||
Assert.AreEqual(5.56789e+0, (double)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.Exists,
|
||||
Path = new List<PathFilter>
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new FieldFilter
|
||||
{
|
||||
@@ -64,7 +64,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.Exists,
|
||||
Path = new List<PathFilter>
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new FieldFilter
|
||||
{
|
||||
@@ -111,7 +111,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.Exists,
|
||||
Path = new List<PathFilter>
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new FieldFilter
|
||||
{
|
||||
@@ -122,7 +122,7 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.Exists,
|
||||
Path = new List<PathFilter>
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new FieldFilter
|
||||
{
|
||||
@@ -164,8 +164,8 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
BooleanQueryExpression e1 = new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.LessThan,
|
||||
Value = new JValue(3),
|
||||
Path = new List<PathFilter>
|
||||
Right = new JValue(3),
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new ArrayIndexFilter()
|
||||
}
|
||||
@@ -179,8 +179,8 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
BooleanQueryExpression e2 = new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.LessThanOrEquals,
|
||||
Value = new JValue(3),
|
||||
Path = new List<PathFilter>
|
||||
Right = new JValue(3),
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new ArrayIndexFilter()
|
||||
}
|
||||
|
||||
@@ -423,6 +423,63 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
};
|
||||
}
|
||||
|
||||
private bool TryParseExpression(out List<PathFilter> expressionPath)
|
||||
{
|
||||
if (_expression[_currentIndex] == '$')
|
||||
{
|
||||
expressionPath = new List<PathFilter>();
|
||||
expressionPath.Add(RootFilter.Instance);
|
||||
}
|
||||
else if (_expression[_currentIndex] == '@')
|
||||
{
|
||||
expressionPath = new List<PathFilter>();
|
||||
}
|
||||
else
|
||||
{
|
||||
expressionPath = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
_currentIndex++;
|
||||
|
||||
if (ParsePath(expressionPath, _currentIndex, true))
|
||||
{
|
||||
throw new JsonException("Path ended with open query.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private JsonException ThrowUnexpectedCharacterException()
|
||||
{
|
||||
return new JsonException("Unexpected character while parsing path query: " + _expression[_currentIndex]);
|
||||
}
|
||||
|
||||
private object ParseSide()
|
||||
{
|
||||
EatWhitespace();
|
||||
|
||||
List<PathFilter> expressionPath;
|
||||
if (TryParseExpression(out expressionPath))
|
||||
{
|
||||
EatWhitespace();
|
||||
EnsureLength("Path ended with open query.");
|
||||
|
||||
return expressionPath;
|
||||
}
|
||||
|
||||
object value;
|
||||
if (TryParseValue(out value))
|
||||
{
|
||||
EatWhitespace();
|
||||
EnsureLength("Path ended with open query.");
|
||||
|
||||
return new JValue(value);
|
||||
}
|
||||
|
||||
throw ThrowUnexpectedCharacterException();
|
||||
}
|
||||
|
||||
private QueryExpression ParseExpression()
|
||||
{
|
||||
QueryExpression rootExpression = null;
|
||||
@@ -430,31 +487,10 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
|
||||
while (_currentIndex < _expression.Length)
|
||||
{
|
||||
EatWhitespace();
|
||||
|
||||
List<PathFilter> expressionPath = new List<PathFilter>();
|
||||
|
||||
if (_expression[_currentIndex] == '$')
|
||||
{
|
||||
expressionPath.Add(RootFilter.Instance);
|
||||
}
|
||||
else if (_expression[_currentIndex] != '@')
|
||||
{
|
||||
throw new JsonException("Unexpected character while parsing path query: " + _expression[_currentIndex]);
|
||||
}
|
||||
|
||||
_currentIndex++;
|
||||
|
||||
if (ParsePath(expressionPath, _currentIndex, true))
|
||||
{
|
||||
throw new JsonException("Path ended with open query.");
|
||||
}
|
||||
|
||||
EatWhitespace();
|
||||
EnsureLength("Path ended with open query.");
|
||||
object left = ParseSide();
|
||||
object right = null;
|
||||
|
||||
QueryOperator op;
|
||||
object value = null;
|
||||
if (_expression[_currentIndex] == ')'
|
||||
|| _expression[_currentIndex] == '|'
|
||||
|| _expression[_currentIndex] == '&')
|
||||
@@ -465,20 +501,14 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
op = ParseOperator();
|
||||
|
||||
EatWhitespace();
|
||||
EnsureLength("Path ended with open query.");
|
||||
|
||||
value = ParseValue();
|
||||
|
||||
EatWhitespace();
|
||||
EnsureLength("Path ended with open query.");
|
||||
right = ParseSide();
|
||||
}
|
||||
|
||||
BooleanQueryExpression booleanExpression = new BooleanQueryExpression
|
||||
{
|
||||
Path = expressionPath,
|
||||
Left = left,
|
||||
Operator = op,
|
||||
Value = (op != QueryOperator.Exists) ? new JValue(value) : null
|
||||
Right = right
|
||||
};
|
||||
|
||||
if (_expression[_currentIndex] == ')')
|
||||
@@ -491,8 +521,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
|
||||
return booleanExpression;
|
||||
}
|
||||
if (_expression[_currentIndex] == '&' && Match("&&"))
|
||||
if (_expression[_currentIndex] == '&')
|
||||
{
|
||||
if (!Match("&&"))
|
||||
{
|
||||
throw ThrowUnexpectedCharacterException();
|
||||
}
|
||||
|
||||
if (parentExpression == null || parentExpression.Operator != QueryOperator.And)
|
||||
{
|
||||
CompositeExpression andExpression = new CompositeExpression { Operator = QueryOperator.And };
|
||||
@@ -512,8 +547,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
|
||||
parentExpression.Expressions.Add(booleanExpression);
|
||||
}
|
||||
if (_expression[_currentIndex] == '|' && Match("||"))
|
||||
if (_expression[_currentIndex] == '|')
|
||||
{
|
||||
if (!Match("||"))
|
||||
{
|
||||
throw ThrowUnexpectedCharacterException();
|
||||
}
|
||||
|
||||
if (parentExpression == null || parentExpression.Operator != QueryOperator.Or)
|
||||
{
|
||||
CompositeExpression orExpression = new CompositeExpression { Operator = QueryOperator.Or };
|
||||
@@ -538,12 +578,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
throw new JsonException("Path ended with open query.");
|
||||
}
|
||||
|
||||
private object ParseValue()
|
||||
private bool TryParseValue(out object value)
|
||||
{
|
||||
char currentChar = _expression[_currentIndex];
|
||||
if (currentChar == '\'')
|
||||
{
|
||||
return ReadQuotedString();
|
||||
value = ReadQuotedString();
|
||||
return true;
|
||||
}
|
||||
else if (char.IsDigit(currentChar) || currentChar == '-')
|
||||
{
|
||||
@@ -561,26 +602,16 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
if (numberText.IndexOfAny(new char[] { '.', 'E', 'e' }) != -1)
|
||||
{
|
||||
double d;
|
||||
if (double.TryParse(numberText, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out d))
|
||||
{
|
||||
return d;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonException("Could not read query value.");
|
||||
}
|
||||
bool result = double.TryParse(numberText, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out d);
|
||||
value = d;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
long l;
|
||||
if (long.TryParse(numberText, NumberStyles.Integer, CultureInfo.InvariantCulture, out l))
|
||||
{
|
||||
return l;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonException("Could not read query value.");
|
||||
}
|
||||
bool result = long.TryParse(numberText, NumberStyles.Integer, CultureInfo.InvariantCulture, out l);
|
||||
value = l;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -594,6 +625,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
if (Match("true"))
|
||||
{
|
||||
value = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -601,18 +633,21 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
if (Match("false"))
|
||||
{
|
||||
return false;
|
||||
value = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (currentChar == 'n')
|
||||
{
|
||||
if (Match("null"))
|
||||
{
|
||||
return null;
|
||||
value = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
throw new JsonException("Could not read query value.");
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private string ReadQuotedString()
|
||||
|
||||
@@ -66,69 +66,45 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
|
||||
internal class BooleanQueryExpression : QueryExpression
|
||||
{
|
||||
public List<PathFilter> Path { get; set; }
|
||||
public JValue Value { get; set; }
|
||||
public object Left { get; set; }
|
||||
public object Right { get; set; }
|
||||
|
||||
private IEnumerable<JToken> GetResult(JToken root, JToken t, object o)
|
||||
{
|
||||
JToken resultToken = o as JToken;
|
||||
if (resultToken != null)
|
||||
{
|
||||
return new[] { resultToken };
|
||||
}
|
||||
|
||||
List<PathFilter> pathFilters = o as List<PathFilter>;
|
||||
if (pathFilters != null)
|
||||
{
|
||||
return JPath.Evaluate(pathFilters, root, t, false);
|
||||
}
|
||||
|
||||
return new JToken[0];
|
||||
}
|
||||
|
||||
public override bool IsMatch(JToken root, JToken t)
|
||||
{
|
||||
IEnumerable<JToken> pathResult = JPath.Evaluate(Path, root, t, false);
|
||||
IEnumerable<JToken> rightResults = GetResult(root, t, Right);
|
||||
IEnumerable<JToken> leftResults = GetResult(root, t, Left);
|
||||
|
||||
foreach (JToken r in pathResult)
|
||||
foreach (JToken leftResult in leftResults)
|
||||
{
|
||||
JValue v = r as JValue;
|
||||
if (v != null)
|
||||
if (Operator == QueryOperator.Exists)
|
||||
{
|
||||
switch (Operator)
|
||||
{
|
||||
case QueryOperator.Equals:
|
||||
if (EqualsWithStringCoercion(v, Value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.NotEquals:
|
||||
if (!EqualsWithStringCoercion(v, Value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.GreaterThan:
|
||||
if (v.CompareTo(Value) > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.GreaterThanOrEquals:
|
||||
if (v.CompareTo(Value) >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.LessThan:
|
||||
if (v.CompareTo(Value) < 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.LessThanOrEquals:
|
||||
if (v.CompareTo(Value) <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.Exists:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Operator)
|
||||
foreach (JToken rightResult in rightResults)
|
||||
{
|
||||
case QueryOperator.Exists:
|
||||
// you can only specify primative types in a comparison
|
||||
// notequals will always be true
|
||||
case QueryOperator.NotEquals:
|
||||
if (MatchTokens(leftResult, rightResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,6 +112,70 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool MatchTokens(JToken leftResult, JToken rightResult)
|
||||
{
|
||||
JValue leftValue = leftResult as JValue;
|
||||
JValue rightValue = rightResult as JValue;
|
||||
|
||||
if (leftValue != null && rightValue != null)
|
||||
{
|
||||
switch (Operator)
|
||||
{
|
||||
case QueryOperator.Equals:
|
||||
if (EqualsWithStringCoercion(leftValue, rightValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.NotEquals:
|
||||
if (!EqualsWithStringCoercion(leftValue, rightValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.GreaterThan:
|
||||
if (leftValue.CompareTo(rightValue) > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.GreaterThanOrEquals:
|
||||
if (leftValue.CompareTo(rightValue) >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.LessThan:
|
||||
if (leftValue.CompareTo(rightValue) < 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.LessThanOrEquals:
|
||||
if (leftValue.CompareTo(rightValue) <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.Exists:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Operator)
|
||||
{
|
||||
case QueryOperator.Exists:
|
||||
// you can only specify primative types in a comparison
|
||||
// notequals will always be true
|
||||
case QueryOperator.NotEquals:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool EqualsWithStringCoercion(JValue value, JValue queryValue)
|
||||
{
|
||||
if (value.Equals(queryValue))
|
||||
|
||||
Reference in New Issue
Block a user