-JsonPath++

This commit is contained in:
James Newton-King
2013-11-17 00:22:02 +13:00
parent 5ce7d8d3dc
commit 042c2b3024
6 changed files with 593 additions and 75 deletions
@@ -355,6 +355,111 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
Assert.AreEqual("Jeff", a2);
}
[Test]
public void ExistsQuery()
{
JArray a = new JArray(new JObject(new JProperty("hi", "ho")), new JObject(new JProperty("hi2", "ha")));
IList<JToken> t = a.SelectTokens("[ ?( @.hi ) ]").ToList();
Assert.IsNotNull(t);
Assert.AreEqual(1, t.Count);
Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("hi", "ho")), t[0]));
}
[Test]
public void EqualsQuery()
{
JArray a = new JArray(
new JObject(new JProperty("hi", "ho")),
new JObject(new JProperty("hi", "ha")));
IList<JToken> t = a.SelectTokens("[ ?( @.['hi'] == 'ha' ) ]").ToList();
Assert.IsNotNull(t);
Assert.AreEqual(1, t.Count);
Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("hi", "ha")), t[0]));
}
[Test]
public void NotEqualsQuery()
{
JArray a = new JArray(
new JArray(new JObject(new JProperty("hi", "ho"))),
new JArray(new JObject(new JProperty("hi", "ha"))));
IList<JToken> t = a.SelectTokens("[ ?( @..hi <> 'ha' ) ]").ToList();
Assert.IsNotNull(t);
Assert.AreEqual(1, t.Count);
Assert.IsTrue(JToken.DeepEquals(new JArray(new JObject(new JProperty("hi", "ho"))), t[0]));
}
[Test]
public void NoPathQuery()
{
JArray a = new JArray(1, 2, 3);
IList<JToken> t = a.SelectTokens("[ ?( @ > 1 ) ]").ToList();
Assert.IsNotNull(t);
Assert.AreEqual(2, t.Count);
Assert.AreEqual(2, (int)t[0]);
Assert.AreEqual(3, (int)t[1]);
}
[Test]
public void GreaterQuery()
{
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("[ ?( @.hi > 1 ) ]").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]));
}
[Test]
public void GreaterOrEqualQuery()
{
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("[ ?( @.hi >= 1 ) ]").ToList();
Assert.IsNotNull(t);
Assert.AreEqual(3, t.Count);
Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("hi", 1)), t[0]));
Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("hi", 2)), t[1]));
Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("hi", 3)), t[2]));
}
[Test]
public void NestedQuery()
{
JArray a = new JArray(
new JObject(
new JProperty("name", "Bad Boys"),
new JProperty("cast", new JArray(
new JObject(new JProperty("name", "Will Smith"))))),
new JObject(
new JProperty("name", "Independence Day"),
new JProperty("cast", new JArray(
new JObject(new JProperty("name", "Will Smith"))))),
new JObject(
new JProperty("name", "The Rock"),
new JProperty("cast", new JArray(
new JObject(new JProperty("name", "Nick Cage")))))
);
IList<JToken> t = a.SelectTokens("[?(@.cast[?(@.name=='Will Smith')])].name").ToList();
Assert.IsNotNull(t);
Assert.AreEqual(2, t.Count);
Assert.AreEqual("Bad Boys", (string)t[0]);
Assert.AreEqual("Independence Day", (string)t[1]);
}
[Test]
public void PathWithConstructor()
{
@@ -38,7 +38,6 @@ using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
namespace Newtonsoft.Json.Tests.Linq.JsonPath
@@ -211,13 +210,184 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
}
[Test]
public void SinglePropertyAndFilter()
public void SinglePropertyAndExistsQuery()
{
JPath path = new JPath("Blah[?(@.name=='hi')]");
JPath path = new JPath("Blah[ ?( @..name ) ]");
Assert.AreEqual(2, path.Filters.Count);
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
List<object> expressions = ((QueryFilter)path.Filters[1]).Expression;
List<QueryExpression> expressions = ((QueryFilter)path.Filters[1]).Expression;
Assert.AreEqual(1, expressions.Count);
Assert.AreEqual(QueryOperator.Exists, expressions[0].Operator);
Assert.AreEqual(1, expressions[0].Path.Count);
Assert.AreEqual("name", ((ScanFilter)expressions[0].Path[0]).Name);
}
[Test]
public void SinglePropertyAndFilterWithWhitespace()
{
JPath path = new JPath("Blah[ ?( @.name=='hi' ) ]");
Assert.AreEqual(2, path.Filters.Count);
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
List<QueryExpression> expressions = ((QueryFilter)path.Filters[1]).Expression;
Assert.AreEqual(1, expressions.Count);
Assert.AreEqual(QueryOperator.Equals, expressions[0].Operator);
Assert.AreEqual("hi", (string)expressions[0].Value);
}
[Test]
public void SinglePropertyAndFilterWithEscapeQuote()
{
JPath path = new JPath(@"Blah[ ?( @.name=='h\'i' ) ]");
Assert.AreEqual(2, path.Filters.Count);
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
List<QueryExpression> expressions = ((QueryFilter)path.Filters[1]).Expression;
Assert.AreEqual(1, expressions.Count);
Assert.AreEqual(QueryOperator.Equals, expressions[0].Operator);
Assert.AreEqual("h'i", (string)expressions[0].Value);
}
[Test]
public void SinglePropertyAndFilterWithDoubleEscape()
{
JPath path = new JPath(@"Blah[ ?( @.name=='h\\i' ) ]");
Assert.AreEqual(2, path.Filters.Count);
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
List<QueryExpression> expressions = ((QueryFilter)path.Filters[1]).Expression;
Assert.AreEqual(1, expressions.Count);
Assert.AreEqual(QueryOperator.Equals, expressions[0].Operator);
Assert.AreEqual("h\\i", (string)expressions[0].Value);
}
[Test]
public void SinglePropertyAndFilterWithUnknownEscape()
{
ExceptionAssert.Throws<JsonException>(
@"Unknown escape chracter: \i",
() => { new JPath(@"Blah[ ?( @.name=='h\i' ) ]"); });
}
[Test]
public void SinglePropertyAndFilterWithFalse()
{
JPath path = new JPath("Blah[ ?( @.name==false ) ]");
Assert.AreEqual(2, path.Filters.Count);
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
List<QueryExpression> expressions = ((QueryFilter)path.Filters[1]).Expression;
Assert.AreEqual(1, expressions.Count);
Assert.AreEqual(QueryOperator.Equals, expressions[0].Operator);
Assert.AreEqual(false, (bool)expressions[0].Value);
}
[Test]
public void SinglePropertyAndFilterWithTrue()
{
JPath path = new JPath("Blah[ ?( @.name==true ) ]");
Assert.AreEqual(2, path.Filters.Count);
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
List<QueryExpression> expressions = ((QueryFilter)path.Filters[1]).Expression;
Assert.AreEqual(1, expressions.Count);
Assert.AreEqual(QueryOperator.Equals, expressions[0].Operator);
Assert.AreEqual(true, (bool)expressions[0].Value);
}
[Test]
public void SinglePropertyAndFilterWithNull()
{
JPath path = new JPath("Blah[ ?( @.name==null ) ]");
Assert.AreEqual(2, path.Filters.Count);
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
List<QueryExpression> expressions = ((QueryFilter)path.Filters[1]).Expression;
Assert.AreEqual(1, expressions.Count);
Assert.AreEqual(QueryOperator.Equals, expressions[0].Operator);
Assert.AreEqual(null, expressions[0].Value.Value);
}
[Test]
public void FilterWithScan()
{
JPath path = new JPath("[?(@..name<>null)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual("name", ((ScanFilter)expressions[0].Path[0]).Name);
}
[Test]
public void FilterWithNotEquals()
{
JPath path = new JPath("[?(@.name<>null)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(QueryOperator.NotEquals, expressions[0].Operator);
}
[Test]
public void FilterWithNotEquals2()
{
JPath path = new JPath("[?(@.name!=null)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(QueryOperator.NotEquals, expressions[0].Operator);
}
[Test]
public void FilterWithLessThan()
{
JPath path = new JPath("[?(@.name<null)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(QueryOperator.LessThan, expressions[0].Operator);
}
[Test]
public void FilterWithLessThanOrEquals()
{
JPath path = new JPath("[?(@.name<=null)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(QueryOperator.LessThanOrEquals, expressions[0].Operator);
}
[Test]
public void FilterWithGreaterThan()
{
JPath path = new JPath("[?(@.name>null)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(QueryOperator.GreaterThan, expressions[0].Operator);
}
[Test]
public void FilterWithGreaterThanOrEquals()
{
JPath path = new JPath("[?(@.name>=null)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(QueryOperator.GreaterThanOrEquals, expressions[0].Operator);
}
[Test]
public void FilterWithInteger()
{
JPath path = new JPath("[?(@.name>=12)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(12, (int)expressions[0].Value);
}
[Test]
public void FilterWithNegativeInteger()
{
JPath path = new JPath("[?(@.name>=-12)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(-12, (int)expressions[0].Value);
}
[Test]
public void FilterWithFloat()
{
JPath path = new JPath("[?(@.name>=12.1)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(12.1d, (double)expressions[0].Value);
}
[Test]
public void FilterWithFloatExp()
{
JPath path = new JPath("[?(@.name>=5.56789e+0)]");
List<QueryExpression> expressions = ((QueryFilter)path.Filters[0]).Expression;
Assert.AreEqual(5.56789e+0, (double)expressions[0].Value);
}
[Test]
@@ -14,14 +14,11 @@ namespace Newtonsoft.Json.Linq.JsonPath
if (Step == 0)
throw new JsonException("Step cannot be zero.");
// todo error when no match
foreach (JToken t in current)
{
IList<JToken> sourceCollection = t as IList<JToken> ?? new List<JToken>(t);
// nothing to slice
if (sourceCollection.Count == 0)
yield break;
// set defaults for null arguments
int stepCount = Step ?? 1;
int startIndex = Start ?? ((stepCount > 0) ? 0 : sourceCollection.Count - 1);
@@ -19,10 +19,11 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
JToken v = o[Name];
if (v == null && errorWhenNoMatch)
throw new JsonException("Property '{0}' does not exist on JObject.".FormatWith(CultureInfo.InvariantCulture, Name));
if (v != null)
yield return v;
yield return v;
if (errorWhenNoMatch)
throw new JsonException("Property '{0}' does not exist on JObject.".FormatWith(CultureInfo.InvariantCulture, Name));
}
else
{
+233 -62
View File
@@ -27,6 +27,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Newtonsoft.Json.Utilities;
@@ -51,8 +52,6 @@ namespace Newtonsoft.Json.Linq.JsonPath
private void ParseMain()
{
int currentPartStartIndex = _currentIndex;
bool followingIndexer = false;
bool scan = false;
if (_expression.Length == 0)
return;
@@ -68,20 +67,27 @@ namespace Newtonsoft.Json.Linq.JsonPath
if (_expression[_currentIndex] != '.')
throw new JsonException("Unexpected character while parsing path: " + _expression[_currentIndex]);
_currentIndex++;
EnsureLength("Unexpected end while parsing path.");
if (_expression[_currentIndex] == '.')
{
scan = true;
_currentIndex++;
}
currentPartStartIndex = _currentIndex;
}
while (_currentIndex < _expression.Length)
if (!ParsePath(Filters, currentPartStartIndex, false))
{
int lastCharacterIndex = _currentIndex;
EatWhitespace();
if (_currentIndex < _expression.Length)
throw new JsonException("Unexpected character while parsing path: " + _expression[lastCharacterIndex]);
}
}
private bool ParsePath(List<PathFilter> filters, int currentPartStartIndex, bool query)
{
bool scan = false;
bool followingIndexer = false;
bool ended = false;
while (_currentIndex < _expression.Length && !ended)
{
char currentChar = _expression[_currentIndex];
@@ -93,22 +99,23 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex);
PathFilter filter = (scan) ? (PathFilter)new ScanFilter() { Name = member } : new FieldFilter() { Name = member };
Filters.Add(filter);
filters.Add(filter);
scan = false;
}
ParseIndexer(currentChar);
filters.Add(ParseIndexer(currentChar));
_currentIndex++;
currentPartStartIndex = _currentIndex;
followingIndexer = true;
break;
case ']':
case ')':
throw new JsonException("Unexpected character while parsing path: " + currentChar);
ended = true;
break;
case ' ':
EatWhitespace();
//EatWhitespace();
if (_currentIndex < _expression.Length)
throw new JsonException("Unexpected character while parsing path: " + currentChar);
ended = true;
break;
case '.':
if (_currentIndex > currentPartStartIndex)
@@ -117,7 +124,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
if (member == "*")
member = null;
PathFilter filter = (scan) ? (PathFilter)new ScanFilter() { Name = member } : new FieldFilter() { Name = member };
Filters.Add(filter);
filters.Add(filter);
scan = false;
}
if (_currentIndex + 1 < _expression.Length && _expression[_currentIndex + 1] == '.')
@@ -130,10 +137,17 @@ namespace Newtonsoft.Json.Linq.JsonPath
followingIndexer = false;
break;
default:
if (followingIndexer)
throw new JsonException("Unexpected character following indexer: " + currentChar);
if (query && (currentChar == '=' || currentChar == '<' || currentChar == '!' || currentChar == '>'))
{
ended = true;
}
else
{
if (followingIndexer)
throw new JsonException("Unexpected character following indexer: " + currentChar);
_currentIndex++;
_currentIndex++;
}
break;
}
}
@@ -144,11 +158,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
if (member == "*")
member = null;
PathFilter filter = (scan) ? (PathFilter)new ScanFilter() { Name = member } : new FieldFilter() { Name = member };
Filters.Add(filter);
filters.Add(filter);
}
return (_currentIndex == _expression.Length);
}
private void ParseIndexer(char indexerOpenChar)
private PathFilter ParseIndexer(char indexerOpenChar)
{
_currentIndex++;
@@ -160,19 +176,19 @@ namespace Newtonsoft.Json.Linq.JsonPath
if (_expression[_currentIndex] == '\'')
{
ParseQuotedField(indexerCloseChar);
return ParseQuotedField(indexerCloseChar);
}
else if (_expression[_currentIndex] == '?')
{
ParseQuery(indexerCloseChar);
return ParseQuery(indexerCloseChar);
}
else
{
ParseArrayIndexer(indexerCloseChar);
return ParseArrayIndexer(indexerCloseChar);
}
}
private void ParseArrayIndexer(char indexerCloseChar)
private PathFilter ParseArrayIndexer(char indexerCloseChar)
{
int start = _currentIndex;
int? end = null;
@@ -206,7 +222,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
int index = Convert.ToInt32(indexer, CultureInfo.InvariantCulture);
indexes.Add(index);
Filters.Add(new ArrayMultipleIndexFilter { Indexes = indexes });
return new ArrayMultipleIndexFilter { Indexes = indexes };
}
else if (colonCount > 0)
{
@@ -221,7 +237,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
step = index;
}
Filters.Add(new ArraySliceFilter { Start = startIndex, End = endIndex, Step = step });
return new ArraySliceFilter { Start = startIndex, End = endIndex, Step = step };
}
else
{
@@ -231,10 +247,8 @@ namespace Newtonsoft.Json.Linq.JsonPath
string indexer = _expression.Substring(start, length);
int index = Convert.ToInt32(indexer, CultureInfo.InvariantCulture);
Filters.Add(new ArrayIndexFilter { Index = index });
return new ArrayIndexFilter { Index = index };
}
return;
} else if (currentCharacter == ',')
{
int length = (end ?? _currentIndex) - start;
@@ -264,8 +278,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
if (_expression[_currentIndex] != indexerCloseChar)
throw new JsonException("Unexpected character while parsing path indexer: " + currentCharacter);
Filters.Add(new ArrayIndexFilter());
return;
return new ArrayIndexFilter();
}
else if (currentCharacter == ':')
{
@@ -321,7 +334,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
}
private void ParseQuery(char indexerCloseChar)
private PathFilter ParseQuery(char indexerCloseChar)
{
_currentIndex++;
EnsureLength("Path ended with open indexer.");
@@ -329,25 +342,27 @@ namespace Newtonsoft.Json.Linq.JsonPath
if (_expression[_currentIndex] != '(')
throw new JsonException("Unexpected character while parsing path indexer: " + _expression[_currentIndex]);
List<object> expressions = new List<object>();
_currentIndex++;
List<QueryExpression> expressions = new List<QueryExpression>();
while (true)
{
ParseExpression();
expressions.Add(string.Empty);
expressions.Add(ParseExpression());
if (_expression[_currentIndex] == ')')
{
_currentIndex++;
EnsureLength("Path ended with open indexer.");
EatWhitespace();
if (_expression[_currentIndex] != indexerCloseChar)
throw new JsonException("Unexpected character while parsing path indexer: " + _expression[_currentIndex]);
Filters.Add(new QueryFilter
return new QueryFilter
{
Expression = expressions
});
return;
};
}
else
{
@@ -356,25 +371,179 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
}
private void ParseExpression()
private QueryExpression ParseExpression()
{
_currentIndex++;
while (_currentIndex < _expression.Length)
{
char currentCharacter = _expression[_currentIndex];
EatWhitespace();
if (currentCharacter == ')')
{
return;
}
else
{
_currentIndex++;
}
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.");
EatWhitespace();
EnsureLength("Path ended with open query.");
QueryOperator op;
object value = null;
if (_expression[_currentIndex] == ')')
{
op = QueryOperator.Exists;
}
else
{
op = ParseOperator();
EatWhitespace();
EnsureLength("Path ended with open query.");
value = ParseValue();
EatWhitespace();
EnsureLength("Path ended with open query.");
}
return new QueryExpression
{
Path = expressionPath,
Operator = op,
Value = (op != QueryOperator.Exists) ? new JValue(value) : null
};
}
private void ParseQuotedField(char indexerCloseChar)
private object ParseValue()
{
char currentChar = _expression[_currentIndex];
if (currentChar == '\'')
{
StringBuilder sb = new StringBuilder();
_currentIndex++;
while (_currentIndex < _expression.Length)
{
currentChar = _expression[_currentIndex];
if (currentChar == '\\' && _currentIndex + 1 < _expression.Length)
{
_currentIndex++;
if (_expression[_currentIndex] == '\'')
sb.Append('\'');
else if (_expression[_currentIndex] == '\\')
sb.Append('\\');
else
throw new JsonException(@"Unknown escape chracter: \" + _expression[_currentIndex]);
_currentIndex++;
}
else if (currentChar == '\'')
{
_currentIndex++;
return sb.ToString();
}
else
{
_currentIndex++;
sb.Append(currentChar);
}
}
}
else if (char.IsDigit(currentChar) || currentChar == '-')
{
StringBuilder sb = new StringBuilder();
sb.Append(currentChar);
_currentIndex++;
while (_currentIndex < _expression.Length)
{
currentChar = _expression[_currentIndex];
if (currentChar == ' ' || currentChar == ')')
{
string numberText = sb.ToString();
if (numberText.IndexOfAny(new char[] { '.', 'E', 'e' }) != -1)
{
double d;
if (double.TryParse(numberText, out d))
return d;
else
throw new JsonException("Could not read query value.");
}
else
{
long l;
if (long.TryParse(numberText, out l))
return l;
else
throw new JsonException("Could not read query value.");
}
}
else
{
sb.Append(currentChar);
_currentIndex++;
}
}
}
else if (currentChar == 't')
{
if (Match("true"))
return true;
}
else if (currentChar == 'f')
{
if (Match("false"))
return false;
}
else if (currentChar == 'n')
{
if (Match("null"))
return null;
}
throw new JsonException("Could not read query value.");
}
private bool Match(string s)
{
int currentPosition = _currentIndex;
foreach (char c in s)
{
if (currentPosition < _expression.Length && _expression[currentPosition] == c)
currentPosition++;
else
return false;
}
_currentIndex = currentPosition;
return true;
}
private QueryOperator ParseOperator()
{
if (_currentIndex + 1 >= _expression.Length)
throw new JsonException("Path ended with open query.");
if (Match("=="))
return QueryOperator.Equals;
if (Match("!=") || Match("<>"))
return QueryOperator.NotEquals;
if (Match("<="))
return QueryOperator.LessThanOrEquals;
if (Match("<"))
return QueryOperator.LessThan;
if (Match(">="))
return QueryOperator.GreaterThanOrEquals;
if (Match(">"))
return QueryOperator.GreaterThan;
throw new JsonException("Could not read query operator.");
}
private FieldFilter ParseQuotedField(char indexerCloseChar)
{
_currentIndex++;
int start = _currentIndex;
@@ -398,9 +567,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
throw new JsonException("Unexpected character while parsing path indexer: " + currentCharacter);
string indexer = _expression.Substring(start, length);
Filters.Add(new FieldFilter { Name = indexer });
return;
return new FieldFilter { Name = indexer };
}
_currentIndex++;
@@ -415,11 +582,15 @@ namespace Newtonsoft.Json.Linq.JsonPath
throw new JsonException(message);
}
internal IEnumerable<JToken> Evaluate(JToken root, bool errorWhenNoMatch)
internal IEnumerable<JToken> Evaluate(JToken t, bool errorWhenNoMatch)
{
IEnumerable<JToken> current = new [] { root };
return Evaluate(Filters, t, errorWhenNoMatch);
}
foreach (PathFilter filter in Filters)
internal static IEnumerable<JToken> Evaluate(List<PathFilter> filters, JToken t, bool errorWhenNoMatch)
{
IEnumerable<JToken> current = new[] { t };
foreach (PathFilter filter in filters)
{
current = filter.ExecuteFilter(current, errorWhenNoMatch);
}
@@ -1,14 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Newtonsoft.Json.Linq.JsonPath
{
internal enum QueryOperator
{
None,
Equals,
NotEquals,
Exists,
LessThan,
LessThanOrEquals,
GreaterThan,
GreaterThanOrEquals
}
internal class QueryExpression
{
public List<PathFilter> Path { get; set; }
public QueryOperator Operator { get; set; }
public JValue Value { get; set; }
}
internal class QueryFilter : PathFilter
{
public List<object> Expression { get; set; }
public List<QueryExpression> Expression { get; set; }
public override IEnumerable<JToken> ExecuteFilter(IEnumerable<JToken> current, bool errorWhenNoMatch)
{
throw new System.NotImplementedException();
foreach (JToken t in current)
{
foreach (JToken v in t)
{
if (Evaluate(errorWhenNoMatch, v))
yield return v;
}
}
}
private bool Evaluate(bool errorWhenNoMatch, JToken value)
{
foreach (QueryExpression expression in Expression)
{
IEnumerable<JToken> pathResult = JPath.Evaluate(expression.Path, value, errorWhenNoMatch);
foreach (JToken r in pathResult)
{
JValue v = r as JValue;
switch (expression.Operator)
{
case QueryOperator.Equals:
if (v != null && v.Equals(expression.Value))
return true;
break;
case QueryOperator.NotEquals:
if (v != null && !v.Equals(expression.Value))
return true;
break;
case QueryOperator.GreaterThan:
if (v != null && v.CompareTo(expression.Value) > 0)
return true;
break;
case QueryOperator.GreaterThanOrEquals:
if (v != null && v.CompareTo(expression.Value) >= 0)
return true;
break;
case QueryOperator.LessThan:
if (v != null && v.CompareTo(expression.Value) < 0)
return true;
break;
case QueryOperator.LessThanOrEquals:
if (v != null && v.CompareTo(expression.Value) <= 0)
return true;
break;
case QueryOperator.Exists:
return true;
default:
throw new ArgumentOutOfRangeException();
}
}
}
return false;
}
}
}