Browse Source

Removed % prefix from path functions.

pull/183/merge
Kalle Stenflo 9 years ago
parent
commit
33f365ef20
  1. 14
      README.md
  2. 5
      json-path/src/main/java/com/jayway/jsonpath/JsonPath.java
  3. 45
      json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java
  4. 7
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java
  5. 12
      json-path/src/main/java/com/jayway/jsonpath/internal/token/FunctionPathToken.java
  6. 6
      json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java
  7. 9
      json-path/src/test/java/com/jayway/jsonpath/FilterTest.java
  8. 10
      json-path/src/test/java/com/jayway/jsonpath/functions/JSONEntityFunctionTest.java
  9. 12
      json-path/src/test/java/com/jayway/jsonpath/functions/NumericFunctionTest.java

14
README.md

@ -62,7 +62,7 @@ Operators
| `[?(<expression>)]` | Filter expression. Expression must evaluate to a boolean value. |
<!---
Functions (not released yet)
Functions
---------
Functions can be invoked at the tail end of a path - the input to a function is the output of the path expression.
@ -70,11 +70,11 @@ The function output is dictated by the function itself.
| Function | Description | Output |
| :------------------------ | :----------------------------------------------------------------- |-----------|
| %min() | Provides the min value of an array of numbers | Double |
| %max() | Provides the max value of an array of numbers | Double |
| %avg() | Provides the average value of an array of numbers | Double |
| %stddev() | Provides the standard deviation value of an array of numbers | Double |
| %length() | Provides the length of an array | Integer |
| min() | Provides the min value of an array of numbers | Double |
| max() | Provides the max value of an array of numbers | Double |
| avg() | Provides the average value of an array of numbers | Double |
| stddev() | Provides the standard deviation value of an array of numbers | Double |
| length() | Provides the length of an array | Integer |
-->
Path Examples
@ -141,7 +141,7 @@ Given the json
| <a href="http://jsonpath.herokuapp.com/?path=$..book[?(@.author =~ /.*REES/i)]" target="_blank">$..book[?(@.author =~ /.*REES/i)]</a> | All books matching regex (ignore case) |
| <a href="http://jsonpath.herokuapp.com/?path=$..*" target="_blank">$..*</a> | Give me every thing
<!---
| <a href="http://jsonpath.herokuapp.com/?path=$..book.%length()" target="_blank">$..book.%length()</a> | The number of books |
| <a href="http://jsonpath.herokuapp.com/?path=$..book.length()" target="_blank">$..book.%length()</a> | The number of books |
-->
Reading a Document
------------------

5
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()){

45
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<Predicate> 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);
}

7
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;
}

12
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;
}
}

6
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'] =~ /.*?/)]");

9
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);
}
}

10
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

12
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);
// }
}

Loading…
Cancel
Save