diff --git a/README.md b/README.md index 000ef138..c819da45 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Operators | `[?()]` | Filter expression. Expression must evaluate to a boolean value. | Path Examples @@ -141,7 +141,7 @@ Given the json | $..book[?(@.author =~ /.*REES/i)] | All books matching regex (ignore case) | | $..* | Give me every thing Reading a Document ------------------ diff --git a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java index a9b9dbf4..732909f2 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java @@ -179,9 +179,10 @@ public class JsonPath { throw new JsonPathException("Options " + AS_PATH_LIST + " and " + ALWAYS_RETURN_LIST + " are not allowed when using path functions!"); } return path.evaluate(jsonObject, jsonObject, configuration).getValue(true); - } - if(optAsPathList){ + + } else if(optAsPathList){ return (T)path.evaluate(jsonObject, jsonObject, configuration).getPath(); + } else { Object res = path.evaluate(jsonObject, jsonObject, configuration).getValue(false); if(optAlwaysReturnList && path.isDefinite()){ diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java index 6b886029..9a9fcb75 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java @@ -24,7 +24,6 @@ public class PathCompiler { private static final char OPEN_SQUARE_BRACKET = '['; private static final char CLOSE_SQUARE_BRACKET = ']'; private static final char OPEN_BRACKET = '('; - private static final char CLOSE_BRACKET = ')'; private static final char WILDCARD = '*'; private static final char PERIOD = '.'; private static final char SPACE = ' '; @@ -33,7 +32,6 @@ public class PathCompiler { private static final char SPLIT = ':'; private static final char MINUS = '-'; private static final char TICK = '\''; - private static final char FUNCTION = '%'; private final LinkedList filterStack; private final CharacterIndex path; @@ -118,42 +116,12 @@ public class PathCompiler { case WILDCARD: return readWildCardToken(appender) || fail("Could not parse token starting at position " + path.position()); - case FUNCTION: - return readFunctionToken(appender) || - fail("Could not parse token starting at position " + path.position()); default: - return readPropertyToken(appender) || + return readPropertyOrFunctionToken(appender) || fail("Could not parse token starting at position " + path.position()); } } - // - // $function() - // - private boolean readFunctionToken(PathTokenAppender appender) { - if (path.currentCharIs(OPEN_SQUARE_BRACKET) || path.currentCharIs(WILDCARD) || path.currentCharIs(PERIOD) || path.currentCharIs(SPACE)) { - return false; - } - int startPosition = path.position(); - int readPosition = startPosition; - int endPosition = 0; - while (path.inBounds(readPosition)) { - char c = path.charAt(readPosition); - if (c == OPEN_BRACKET && path.nextSignificantCharIs(readPosition, CLOSE_BRACKET)) { - endPosition = path.indexOfNextSignificantChar(readPosition, CLOSE_BRACKET); - break; - } - readPosition++; - } - path.setPosition(endPosition); - - String function = path.subSequence(startPosition, endPosition + 1).toString(); - - appender.appendPathToken(PathTokenFactory.createFunctionPathToken(function)); - - return path.currentIsTail(); - } - // // . and .. // @@ -173,9 +141,9 @@ public class PathCompiler { } // - // fooBar + // fooBar or fooBar() // - private boolean readPropertyToken(PathTokenAppender appender) { + private boolean readPropertyOrFunctionToken(PathTokenAppender appender) { if (path.currentCharIs(OPEN_SQUARE_BRACKET) || path.currentCharIs(WILDCARD) || path.currentCharIs(PERIOD) || path.currentCharIs(SPACE)) { return false; } @@ -201,8 +169,11 @@ public class PathCompiler { path.setPosition(endPosition); String property = path.subSequence(startPosition, endPosition).toString(); - - appender.appendPathToken(PathTokenFactory.createSinglePropertyPathToken(property)); + if(property.endsWith("()")){ + appender.appendPathToken(PathTokenFactory.createFunctionPathToken(property)); + } else { + appender.appendPathToken(PathTokenFactory.createSinglePropertyPathToken(property)); + } return path.currentIsTail() || readNextToken(appender); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java index cb4dd835..753e4a99 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java @@ -13,14 +13,14 @@ public class FilterCompiler { private static final Logger logger = LoggerFactory.getLogger(FilterCompiler.class); private static final char DOC_CONTEXT = '$'; - private static final char EVAL_CONTEXT = '@'; + private static final char EVAL_CONTEXT = '@'; /**/ private static final char OPEN_SQUARE_BRACKET = '['; private static final char OPEN_BRACKET = '('; private static final char CLOSE_BRACKET = ')'; private static final char SPACE = ' '; private static final char MINUS = '-'; private static final char TICK = '\''; - private static final char FUNCTION = '%'; + private static final char PERIOD = '.'; private static final char LT = '<'; private static final char GT = '>'; private static final char EQ = '='; @@ -338,7 +338,7 @@ public class FilterCompiler { } idx--; while(filter.inBounds(idx) && idx > lowerBound){ - if(filter.charAt(idx) == FUNCTION){ + if(filter.charAt(idx) == PERIOD){ return true; } idx--; @@ -349,6 +349,7 @@ public class FilterCompiler { private boolean isLogicalOperatorChar(char c) { return c == AND || c == OR; } + private boolean isRelationalOperatorChar(char c) { return c == LT || c == GT || c == EQ || c == TILDE || c == BANG; } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/token/FunctionPathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/token/FunctionPathToken.java index 2323589a..686866f9 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/token/FunctionPathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/token/FunctionPathToken.java @@ -4,9 +4,6 @@ import com.jayway.jsonpath.internal.PathRef; import com.jayway.jsonpath.internal.function.Function; import com.jayway.jsonpath.internal.function.FunctionFactory; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Token representing a Function call to one of the functions produced via the FunctionFactory * @@ -21,12 +18,9 @@ public class FunctionPathToken extends PathToken { public FunctionPathToken(String pathFragment) { this.pathFragment = pathFragment; - Matcher matcher = Pattern.compile(".*?\\%(\\w+)\\(.*?").matcher(pathFragment); - if (matcher.matches()) { - functionName = matcher.group(1); - } - else { - // We'll end up throwing an error from the factory when we get that far + if(pathFragment.endsWith("()")){ + functionName = pathFragment.substring(0, pathFragment.length()-2); + } else { functionName = null; } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java b/json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java index b676ccf8..df202be3 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java @@ -36,9 +36,9 @@ public class FilterCompilerTest { assertThat(compile("[?(@.a IN {'foo':'bar'})]").toString()).isEqualTo("[?(@['a'] IN {'foo':'bar'})]"); assertThat(compile("[?(@.value<'7')]").toString()).isEqualTo("[?(@['value'] < '7')]"); assertThat(compile("[?(@.message == 'it\\\\')]").toString()).isEqualTo("[?(@['message'] == 'it\\\\')]"); - assertThat(compile("[?(@.message.%min() > 10)]").toString()).isEqualTo("[?(@['message'].%min() > 10)]"); - assertThat(compile("[?(@.message.%min()==10)]").toString()).isEqualTo("[?(@['message'].%min() == 10)]"); - assertThat(compile("[?(10 == @.message.%min())]").toString()).isEqualTo("[?(10 == @['message'].%min())]"); + assertThat(compile("[?(@.message.min() > 10)]").toString()).isEqualTo("[?(@['message'].min() > 10)]"); + assertThat(compile("[?(@.message.min()==10)]").toString()).isEqualTo("[?(@['message'].min() == 10)]"); + assertThat(compile("[?(10 == @.message.min())]").toString()).isEqualTo("[?(10 == @['message'].min())]"); assertThat(compile("[?(((@)))]").toString()).isEqualTo("[?(@)]"); assertThat(compile("[?(@.name =~ /.*?/i)]").toString()).isEqualTo("[?(@['name'] =~ /.*?/i)]"); assertThat(compile("[?(@.name =~ /.*?/)]").toString()).isEqualTo("[?(@['name'] =~ /.*?/)]"); diff --git a/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java index dbfea025..b826f958 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java @@ -482,11 +482,8 @@ public class FilterTest extends BaseTest { @Test - public void inline_in_criteria_evalueates() { - - Object read = JsonPath.read(JSON_DOCUMENT, "$.store.book[?(@.category in ['reference', 'fiction'])]"); - - System.out.println(read); - + public void inline_in_criteria_evaluates() { + List list = JsonPath.read(JSON_DOCUMENT, "$.store.book[?(@.category in ['reference', 'fiction'])]"); + assertThat(list).hasSize(4); } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/functions/JSONEntityFunctionTest.java b/json-path/src/test/java/com/jayway/jsonpath/functions/JSONEntityFunctionTest.java index fa7195f6..77e57e81 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/functions/JSONEntityFunctionTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/functions/JSONEntityFunctionTest.java @@ -54,18 +54,18 @@ public class JSONEntityFunctionTest extends BaseFunctionTest { @Test public void testLengthOfTextArray() { // The length of JSONArray is an integer - verifyFunction(conf, "$['text'].%length()", TEXT_SERIES, 6); + verifyFunction(conf, "$['text'].length()", TEXT_SERIES, 6); } @Test public void testLengthOfNumberArray() { // The length of JSONArray is an integer - verifyFunction(conf, "$.numbers.%length()", NUMBER_SERIES, 10); + verifyFunction(conf, "$.numbers.length()", NUMBER_SERIES, 10); } @Test public void testLengthOfStructure() { - verifyFunction(conf, "$.batches.%length()", BATCH_JSON, 2); + verifyFunction(conf, "$.batches.length()", BATCH_JSON, 2); } /** @@ -80,7 +80,7 @@ public class JSONEntityFunctionTest extends BaseFunctionTest { */ @Test public void testPredicateWithFunctionCallSingleMatch() { - String path = "$.batches.results[?(@.values.%length() >= $.batches.minBatchSize)].values.%avg()"; + String path = "$.batches.results[?(@.values.length() >= $.batches.minBatchSize)].values.avg()"; // Its an array because in some use-cases the min size might match more than one batch and thus we'll get // the average out for each collection @@ -91,7 +91,7 @@ public class JSONEntityFunctionTest extends BaseFunctionTest { @Test public void testPredicateWithFunctionCallTwoMatches() { - String path = "$.batches.results[?(@.values.%length() >= 3)].values.%avg()"; + String path = "$.batches.results[?(@.values.length() >= 3)].values.avg()"; // Its an array because in some use-cases the min size might match more than one batch and thus we'll get // the average out for each collection diff --git a/json-path/src/test/java/com/jayway/jsonpath/functions/NumericFunctionTest.java b/json-path/src/test/java/com/jayway/jsonpath/functions/NumericFunctionTest.java index 02202c38..2d38eaa1 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/functions/NumericFunctionTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/functions/NumericFunctionTest.java @@ -42,27 +42,27 @@ public class NumericFunctionTest extends BaseFunctionTest { @Test public void testAverageOfDoubles() { - verifyMathFunction(conf, "$.numbers.%avg()", 5.5); + verifyMathFunction(conf, "$.numbers.avg()", 5.5); } @Test public void testSumOfDouble() { - verifyMathFunction(conf, "$.numbers.%sum()", (10d * (10d + 1d)) / 2d); + verifyMathFunction(conf, "$.numbers.sum()", (10d * (10d + 1d)) / 2d); } @Test public void testMaxOfDouble() { - verifyMathFunction(conf, "$.numbers.%max()", 10d); + verifyMathFunction(conf, "$.numbers.max()", 10d); } @Test public void testMinOfDouble() { - verifyMathFunction(conf, "$.numbers.%min()", 1d); + verifyMathFunction(conf, "$.numbers.min()", 1d); } @Test public void testStdDevOfDouble() { - verifyMathFunction(conf, "$.numbers.%stddev()", 2.8722813232690143d); + verifyMathFunction(conf, "$.numbers.stddev()", 2.8722813232690143d); } /** @@ -73,7 +73,7 @@ public class NumericFunctionTest extends BaseFunctionTest { // public void testInvalidFunctionNameNegative() { // JSONArray numberSeries = new JSONArray(); // numberSeries.addAll(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); -// assertThat(using(conf).parse(NUMBER_SERIES).read("$.numbers.%foo()")).isEqualTo(numberSeries); +// assertThat(using(conf).parse(NUMBER_SERIES).read("$.numbers.foo()")).isEqualTo(numberSeries); // } }