feature: implement new regex equals operator for JsonPath Query expression. Example: Blah[?( @.name =~'/hi/i' )]
This commit is contained in:
@@ -314,6 +314,17 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
Assert.AreEqual("h\\i", (string)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SinglePropertyAndFilterWithRegex()
|
||||
{
|
||||
JPath path = new JPath("Blah[ ?( @.name=~'/hi/i' ) ]");
|
||||
Assert.AreEqual(2, path.Filters.Count);
|
||||
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
|
||||
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
|
||||
Assert.AreEqual(QueryOperator.RegExEquals, expressions.Operator);
|
||||
Assert.AreEqual("/hi/i", (string)(JToken)expressions.Right);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SinglePropertyAndFilterWithUnknownEscape()
|
||||
{
|
||||
|
||||
@@ -157,6 +157,70 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
|
||||
|
||||
Assert.IsFalse(compositeExpression.IsMatch(o3, o3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BooleanExpressionTest_RegExEqualsOperator()
|
||||
{
|
||||
BooleanQueryExpression e1 = new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.RegExEquals,
|
||||
Right = new JValue("/foo.*d/"),
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new ArrayIndexFilter()
|
||||
}
|
||||
};
|
||||
|
||||
Assert.IsTrue(e1.IsMatch(null, new JArray("food")));
|
||||
Assert.IsTrue(e1.IsMatch(null, new JArray("fooood and drink")));
|
||||
Assert.IsFalse(e1.IsMatch(null, new JArray("FOOD")));
|
||||
Assert.IsFalse(e1.IsMatch(null, new JArray("foo", "foog", "good")));
|
||||
|
||||
BooleanQueryExpression e2 = new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.RegExEquals,
|
||||
Right = new JValue("/Foo.*d/i"),
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new ArrayIndexFilter()
|
||||
}
|
||||
};
|
||||
|
||||
Assert.IsTrue(e2.IsMatch(null, new JArray("food")));
|
||||
Assert.IsTrue(e2.IsMatch(null, new JArray("fooood and drink")));
|
||||
Assert.IsTrue(e2.IsMatch(null, new JArray("FOOD")));
|
||||
Assert.IsFalse(e2.IsMatch(null, new JArray("foo", "foog", "good")));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BooleanExpressionTest_RegExEqualsOperator_CornerCase()
|
||||
{
|
||||
BooleanQueryExpression e1 = new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.RegExEquals,
|
||||
Right = new JValue("/// comment/"),
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new ArrayIndexFilter()
|
||||
}
|
||||
};
|
||||
|
||||
Assert.IsTrue(e1.IsMatch(null, new JArray("// comment")));
|
||||
Assert.IsFalse(e1.IsMatch(null, new JArray("//comment", "/ comment")));
|
||||
|
||||
BooleanQueryExpression e2 = new BooleanQueryExpression
|
||||
{
|
||||
Operator = QueryOperator.RegExEquals,
|
||||
Right = new JValue("/<tag>.*</tag>/i"),
|
||||
Left = new List<PathFilter>
|
||||
{
|
||||
new ArrayIndexFilter()
|
||||
}
|
||||
};
|
||||
|
||||
Assert.IsTrue(e2.IsMatch(null, new JArray("<Tag>Test</Tag>", "")));
|
||||
Assert.IsFalse(e2.IsMatch(null, new JArray("<tag>Test<tag>")));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BooleanExpressionTest()
|
||||
|
||||
@@ -728,6 +728,12 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
return QueryOperator.Equals;
|
||||
}
|
||||
|
||||
if (Match("=~"))
|
||||
{
|
||||
return QueryOperator.RegExEquals;
|
||||
}
|
||||
|
||||
if (Match("!=") || Match("<>"))
|
||||
{
|
||||
return QueryOperator.NotEquals;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
#if !HAVE_LINQ
|
||||
using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#else
|
||||
@@ -22,7 +23,8 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
GreaterThan = 6,
|
||||
GreaterThanOrEquals = 7,
|
||||
And = 8,
|
||||
Or = 9
|
||||
Or = 9,
|
||||
RegExEquals = 10
|
||||
}
|
||||
|
||||
internal abstract class QueryExpression
|
||||
@@ -131,6 +133,12 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
{
|
||||
switch (Operator)
|
||||
{
|
||||
case QueryOperator.RegExEquals:
|
||||
if (RegExEquals(leftValue, rightValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QueryOperator.Equals:
|
||||
if (EqualsWithStringCoercion(leftValue, rightValue))
|
||||
{
|
||||
@@ -186,6 +194,35 @@ namespace Newtonsoft.Json.Linq.JsonPath
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool RegExEquals(JValue value, JValue queryValue)
|
||||
{
|
||||
if (queryValue.Type != JTokenType.String || value.Type != JTokenType.String)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var regExArray = ((string)queryValue.Value).Split('/');
|
||||
if (regExArray.Length < 3)
|
||||
{
|
||||
throw new Exception("Syntax error when using regex compare");
|
||||
}
|
||||
|
||||
var trimFirstAndLastMember = regExArray.Skip(1).Take(regExArray.Length - 2).ToArray();
|
||||
var regExQuery = string.Join("/", trimFirstAndLastMember);
|
||||
|
||||
if (regExArray.Last() == string.Empty)
|
||||
{
|
||||
return Regex.IsMatch((string)value.Value, regExQuery);
|
||||
}
|
||||
|
||||
if (regExArray.Last() == "i")
|
||||
{
|
||||
return Regex.IsMatch((string)value.Value, regExQuery, RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
throw new Exception("Syntax error when using regex compare");
|
||||
}
|
||||
|
||||
private bool EqualsWithStringCoercion(JValue value, JValue queryValue)
|
||||
{
|
||||
if (value.Equals(queryValue))
|
||||
|
||||
Reference in New Issue
Block a user