Browse Source

Added access array by variable

pull/10/head
Anton Panasenko 12 years ago
parent
commit
9b9ad0331e
  1. 3
      json-path/src/main/java/com/jayway/jsonpath/JsonModel.java
  2. 3
      json-path/src/main/java/com/jayway/jsonpath/JsonPath.java
  3. 8
      json-path/src/main/java/com/jayway/jsonpath/internal/PathToken.java
  4. 17
      json-path/src/main/java/com/jayway/jsonpath/internal/PathTokenizer.java
  5. 67
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java
  6. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayIndexFilter.java
  7. 6
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayQueryFilter.java
  8. 42
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/FieldFilter.java
  9. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterFactory.java
  10. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/HasFieldFilter.java
  11. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/PassthroughFilter.java
  12. 8
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/PathTokenFilter.java
  13. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ScanFilter.java
  14. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/WildcardFilter.java
  15. 7
      json-path/src/test/java/com/jayway/jsonpath/ArraySlicingTest.java
  16. 23
      json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java

3
json-path/src/main/java/com/jayway/jsonpath/JsonModel.java

@ -575,6 +575,7 @@ public class JsonModel {
}
Object modelRef = jsonObject;
Object root = jsonObject;
if (jsonPath.getTokenizer().size() == 1) {
PathToken onlyToken = jsonPath.getTokenizer().iterator().next();
@ -588,7 +589,7 @@ public class JsonModel {
PathToken currentToken;
do {
currentToken = tokens.poll();
modelRef = currentToken.apply(modelRef, this.configuration);
modelRef = currentToken.apply(modelRef, root, this.configuration);
} while (!tokens.isEmpty());
if (modelRef.getClass().isAssignableFrom(clazz)) {

3
json-path/src/main/java/com/jayway/jsonpath/JsonPath.java

@ -243,6 +243,7 @@ public class JsonPath {
Object result = jsonObject;
Object root = jsonObject;
boolean inArrayContext = false;
@ -253,7 +254,7 @@ public class JsonPath {
LOG.debug("Applying filter: " + filter + " to " + result);
}
result = filter.filter(result, configuration, contextFilters, inArrayContext);
result = filter.filter(result, root, configuration, contextFilters, inArrayContext);
if(result == null && !pathToken.isEndToken()){
throw new PathNotFoundException("Path token: '" + pathToken.getFragment() + "' not found.");

8
json-path/src/main/java/com/jayway/jsonpath/internal/PathToken.java

@ -45,12 +45,12 @@ public class PathToken {
return FilterFactory.createFilter(this);
}
public Object filter(Object model, Configuration configuration){
return FilterFactory.createFilter(this).filter(model, configuration);
public Object filter(Object model, Object root, Configuration configuration){
return FilterFactory.createFilter(this).filter(model, root, configuration);
}
public Object apply(Object model, Configuration configuration){
return FilterFactory.createFilter(this).getRef(model, configuration);
public Object apply(Object model, Object root, Configuration configuration){
return FilterFactory.createFilter(this).getRef(model, root, configuration);
}
public String getFragment() {

17
json-path/src/main/java/com/jayway/jsonpath/internal/PathTokenizer.java

@ -100,6 +100,10 @@ public class PathTokenizer implements Iterable<PathToken> {
return pathChars[index];
}
private char next() {
return pathChars[index+1];
}
private char poll() {
char peek = peek();
index++;
@ -145,9 +149,18 @@ public class PathTokenizer implements Iterable<PathToken> {
StringBuilder sb = new StringBuilder();
while (!isEmpty() && (!isStopChar(peek(), stopChars))) {
if (peek() == '(') {
if (peek() == '[') {
sb.append(poll());
}
while (!isEmpty() && (!isStopChar(peek(), stopChars))) {
if (peek() == '[') {
do {
sb.append(poll());
} while (peek() != ']');
sb.append(poll());
} else if (peek() == '(') {
do {
sb.append(poll());
} while (peek() != ')');

67
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java

@ -32,31 +32,14 @@ public class ArrayEvalFilter extends PathTokenFilter {
private static final Pattern CONDITION_STATEMENT_PATTERN = Pattern.compile("\\[\\s?\\?\\(.*?[!=<>]+.*?\\)\\s?]");
private static final Pattern PATTERN = Pattern.compile("\\s?(@.*?)\\s?([!=<>]+)\\s?(.*?)\\s?");
private ConditionStatement[] conditionStatements;
public ArrayEvalFilter(String condition) {
super(condition);
// [?(@.name == 'Luke Skywalker' && @.occupation == 'Farm boy')]
// [?(@.name == 'Luke Skywalker')]
condition = condition.trim();
condition = condition.substring(3, condition.length()-2);
String[] split = condition.split("&&");
conditionStatements = new ConditionStatement[split.length];
for(int i = 0; i < split.length; i++){
conditionStatements[i] = createConditionStatement(split[i]);
}
}
@Override
public Object filter(Object obj, Configuration configuration) {
public Object filter(Object obj, Object root, Configuration configuration) {
JsonProvider jsonProvider = configuration.getProvider();
Iterable<Object> src = null;
try {
@ -66,7 +49,7 @@ public class ArrayEvalFilter extends PathTokenFilter {
}
Object result = jsonProvider.createArray();
for (Object item : src) {
if (isMatch(item, configuration, conditionStatements)) {
if (isMatch(item, configuration, getConditionStatements(condition, root))) {
jsonProvider.setProperty(result, jsonProvider.length(result), item);
}
}
@ -74,7 +57,7 @@ public class ArrayEvalFilter extends PathTokenFilter {
}
@Override
public Object getRef(Object obj, Configuration configuration) {
public Object getRef(Object obj, Object root, Configuration configuration) {
throw new UnsupportedOperationException("");
}
@ -101,10 +84,39 @@ public class ArrayEvalFilter extends PathTokenFilter {
}
}
private ConditionStatement[] getConditionStatements(String condition, Object root) {
// [?(@.name == 'Luke Skywalker' && @.occupation == 'Farm boy')]
// [?(@.name == 'Luke Skywalker')]
condition = condition.trim();
condition = condition.substring(3, condition.length()-2);
String[] split = condition.split("&&");
ConditionStatement[] conditionStatements = new ConditionStatement[split.length];
for(int i = 0; i < split.length; i++){
conditionStatements[i] = createConditionStatement(split[i], root);
}
return conditionStatements;
}
static boolean isConditionStatement(String condition) {
return CONDITION_STATEMENT_PATTERN.matcher(condition).matches();
}
static ConditionStatement createConditionStatement(String condition, Object root) {
Matcher matcher = PATTERN.matcher(condition);
if (matcher.matches()) {
String property = matcher.group(1).trim();
String operator = matcher.group(2).trim();
String expected = matcher.group(3).trim();
return new ConditionStatement(condition, property, operator, expected, root);
} else {
return null;
}
}
static ConditionStatement createConditionStatement(String condition) {
Matcher matcher = PATTERN.matcher(condition);
if (matcher.matches()) {
@ -112,12 +124,13 @@ public class ArrayEvalFilter extends PathTokenFilter {
String operator = matcher.group(2).trim();
String expected = matcher.group(3).trim();
return new ConditionStatement(condition, property, operator, expected);
return new ConditionStatement(condition, property, operator, expected, "");
} else {
return null;
}
}
static class ConditionStatement {
private final String condition;
private final String field;
@ -126,14 +139,15 @@ public class ArrayEvalFilter extends PathTokenFilter {
private final JsonPath path;
ConditionStatement(String condition, String field, String operator, String expected) {
ConditionStatement(String condition, String field, String operator, String expected, Object root) {
this.condition = condition;
this.field = field;
this.operator = operator;
if(expected.startsWith("'")){
this.expected = trim(expected, 1, 1);
} else if (expected.startsWith("$")) {
this.expected = JsonPath.read(root, expected).toString();
}else{
this.expected = expected;
}
@ -144,8 +158,13 @@ public class ArrayEvalFilter extends PathTokenFilter {
this.path = JsonPath.compile(this.field.replace("@", "$"));
}
}
ConditionStatement(String field, String operator, String expected, Object root) {
this(null, field, operator, expected, root);
}
ConditionStatement(String field, String operator, String expected) {
this(null, field, operator, expected);
this(null, field, operator, expected, "");
}
String getCondition() {

4
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayIndexFilter.java

@ -52,7 +52,7 @@ public class ArrayIndexFilter extends PathTokenFilter {
@Override
public Object filter(Object obj, Configuration configuration) {
public Object filter(Object obj, Object root, Configuration configuration) {
JsonProvider jsonProvider = configuration.getProvider();
Object result = jsonProvider.createArray();
@ -138,7 +138,7 @@ public class ArrayIndexFilter extends PathTokenFilter {
}
@Override
public Object getRef(Object obj, Configuration configuration) {
public Object getRef(Object obj, Object root, Configuration configuration) {
if(SINGLE_ARRAY_INDEX_PATTERN.matcher(condition).matches()){
String trimmedCondition = trim(condition, 1, 1);
return configuration.getProvider().getProperty(obj, trimmedCondition);

6
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayQueryFilter.java

@ -29,18 +29,18 @@ public class ArrayQueryFilter extends PathTokenFilter {
}
@Override
public Object filter(Object obj, Configuration configuration, LinkedList<Filter> filters, boolean inArrayContext) {
public Object filter(Object obj, Object root, Configuration configuration, LinkedList<Filter> filters, boolean inArrayContext) {
Filter filter = filters.poll();
return filter.doFilter(configuration.getProvider().toIterable(obj), configuration);
}
@Override
public Object filter(Object obj, Configuration configuration) {
public Object filter(Object obj, Object root, Configuration configuration) {
throw new UnsupportedOperationException();
}
@Override
public Object getRef(Object obj, Configuration configuration) {
public Object getRef(Object obj, Object root, Configuration configuration) {
throw new UnsupportedOperationException("");
}

42
json-path/src/main/java/com/jayway/jsonpath/internal/filter/FieldFilter.java

@ -14,10 +14,7 @@
*/
package com.jayway.jsonpath.internal.filter;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.*;
import com.jayway.jsonpath.internal.PathToken;
import com.jayway.jsonpath.spi.JsonProvider;
@ -39,10 +36,14 @@ public class FieldFilter extends PathTokenFilter {
}
@Override
public Object filter(Object obj, Configuration configuration, LinkedList<Filter> filters, boolean inArrayContext) {
public Object filter(Object obj, Object root, Configuration configuration, LinkedList<Filter> filters, boolean inArrayContext) {
String condition = getCondition(root);
JsonProvider jsonProvider = configuration.getProvider();
if (jsonProvider.isArray(obj)) {
if (!inArrayContext) {
if (isInt(condition)) {
return new ArrayIndexFilter("[" + condition + "]").filter(obj, root, configuration, filters, inArrayContext);
} else if (!inArrayContext) {
throw new PathNotFoundException("Path '" + condition + "' is being applied to an array. Arrays can not have attributes.");
} else {
Object result = jsonProvider.createArray();
@ -111,20 +112,24 @@ public class FieldFilter extends PathTokenFilter {
}
}
@Override
public Object filter(Object obj, Configuration configuration) {
public Object filter(Object obj, Object root, Configuration configuration) {
String condition = getCondition(root);
JsonProvider jsonProvider = configuration.getProvider();
if (jsonProvider.isArray(obj)) {
return obj;
if (isInt(condition)) {
return new ArrayIndexFilter("[" + condition + "]").filter(obj, root, configuration);
} else {
return obj;
}
} else {
return jsonProvider.getProperty(obj, condition);
}
}
@Override
public Object getRef(Object obj, Configuration configuration) {
return filter(obj, configuration);
public Object getRef(Object obj, Object root, Configuration configuration) {
return filter(obj, root, configuration);
}
@Override
@ -132,5 +137,20 @@ public class FieldFilter extends PathTokenFilter {
return false;
}
public String getCondition(Object root) {
if (condition.startsWith("[$")) {
return JsonPath.read(root, trim(condition, 1, 1)).toString();
} else {
return condition;
}
}
private boolean isInt(String str) {
try {
Integer.parseInt(str);
} catch (NumberFormatException e) {
return false;
}
return true;
}
}

2
json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterFactory.java

@ -68,6 +68,8 @@ public class FilterFactory {
} else {
throw new InvalidPathException("Failed to create PathTokenFilter for path fragment: " + pathFragment);
}
} else if (pathFragment.startsWith("[$")) {
return new FieldFilter(token);
} else {
//[0]
//[0,1, ...]

4
json-path/src/main/java/com/jayway/jsonpath/internal/filter/HasFieldFilter.java

@ -39,7 +39,7 @@ public class HasFieldFilter extends PathTokenFilter {
}
@Override
public Object filter(Object obj, Configuration configuration) {
public Object filter(Object obj, Object root, Configuration configuration) {
JsonProvider jsonProvider = configuration.getProvider();
//[?(@.isbn)]
@ -58,7 +58,7 @@ public class HasFieldFilter extends PathTokenFilter {
}
@Override
public Object getRef(Object obj, Configuration configuration) {
public Object getRef(Object obj, Object root, Configuration configuration) {
throw new UnsupportedOperationException();
}

4
json-path/src/main/java/com/jayway/jsonpath/internal/filter/PassthroughFilter.java

@ -30,12 +30,12 @@ public class PassthroughFilter extends PathTokenFilter {
}
@Override
public Object filter(Object obj, Configuration configuration) {
public Object filter(Object obj, Object root, Configuration configuration) {
return obj;
}
@Override
public Object getRef(Object obj, Configuration configuration) {
public Object getRef(Object obj, Object root, Configuration configuration) {
return obj;
}

8
json-path/src/main/java/com/jayway/jsonpath/internal/filter/PathTokenFilter.java

@ -46,13 +46,13 @@ public abstract class PathTokenFilter {
return res;
}
public Object filter(Object obj, Configuration configuration, LinkedList<Filter> filters, boolean inArrayContext){
return filter(obj, configuration);
public Object filter(Object obj, Object root, Configuration configuration, LinkedList<Filter> filters, boolean inArrayContext){
return filter(obj, root, configuration);
}
public abstract Object filter(Object obj, Configuration configuration);
public abstract Object filter(Object obj, Object root, Configuration configuration);
public abstract Object getRef(Object obj, Configuration configuration);
public abstract Object getRef(Object obj, Object root, Configuration configuration);
public abstract boolean isArrayFilter();

4
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ScanFilter.java

@ -28,7 +28,7 @@ public class ScanFilter extends PathTokenFilter {
}
@Override
public Object filter(Object obj, Configuration configuration) {
public Object filter(Object obj, Object root, Configuration configuration) {
JsonProvider jsonProvider = configuration.getProvider();
Object result = jsonProvider.createArray();
scan(obj, result, jsonProvider);
@ -42,7 +42,7 @@ public class ScanFilter extends PathTokenFilter {
}
@Override
public Object getRef(Object obj, Configuration configuration) {
public Object getRef(Object obj, Object root, Configuration configuration) {
throw new UnsupportedOperationException();
}

4
json-path/src/main/java/com/jayway/jsonpath/internal/filter/WildcardFilter.java

@ -27,7 +27,7 @@ public class WildcardFilter extends PathTokenFilter {
}
@Override
public Object filter(Object obj, Configuration configuration) {
public Object filter(Object obj, Object root, Configuration configuration) {
JsonProvider jsonProvider = configuration.getProvider();
Object result = jsonProvider.createArray();
@ -46,7 +46,7 @@ public class WildcardFilter extends PathTokenFilter {
}
@Override
public Object getRef(Object obj, Configuration configuration) {
public Object getRef(Object obj, Object root, Configuration configuration) {
throw new UnsupportedOperationException();
}

7
json-path/src/test/java/com/jayway/jsonpath/ArraySlicingTest.java

@ -38,7 +38,7 @@ public class ArraySlicingTest {
@Test
public void get_by_position(){
int result = JsonPath.read(JSON_ARRAY, "$[3]");
int result = JsonPath.<Integer>read(JSON_ARRAY, "$[3]");
assertEquals(7, result);
}
@ -76,13 +76,13 @@ public class ArraySlicingTest {
@Test
public void get_from_tail(){
int result = JsonPath.read(JSON_ARRAY, "$[3:]");
int result = JsonPath.<Integer>read(JSON_ARRAY, "$[3:]");
assertEquals(8, result);
}
@Test
public void get_from_tail_length(){
int result = JsonPath.read(JSON_ARRAY, "$[(@.length -3)]");
int result = JsonPath.<Integer>read(JSON_ARRAY, "$[(@.length -3)]");
assertEquals(8, result);
}
@ -91,5 +91,4 @@ public class ArraySlicingTest {
List<Integer> result = JsonPath.read(JSON_ARRAY, "$[0,1,2]");
assertThat(result, Matchers.contains(1,3,5));
}
}

23
json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java

@ -57,6 +57,15 @@ public class JsonPathTest {
" \"foo:bar\": \"fooBar\",\n" +
" \"dot.notation\": \"new\",\n" +
" \"dash-notation\": \"dashes\"\n" +
" },\n" +
" \"foo\": {\n" +
" \"bar\": \"red\",\n" +
" \"red\": [\"bar\"],\n" +
" \"category\": \"reference\",\n" +
" \"category_array\": [\"reference\"],\n" +
" \"bar_hash\": [{\"red\": \"bar\"}],\n" +
" \"one\": 1,\n" +
" \"price\": 10\n" +
" }\n" +
" }\n" +
"}";
@ -180,7 +189,7 @@ public class JsonPathTest {
Map result = JsonPath.read(DOCUMENT, "$.store");
assertEquals(2, result.values().size());
assertEquals(3, result.values().size());
}
@Test
@ -315,7 +324,17 @@ public class JsonPathTest {
}
@Test
public void access_array_by_variable() {
assertEquals(JsonPath.read(DOCUMENT, "$.store.foo[$.store.foo.bar_hash[?(@.red)].red[0]]"), "red");
assertEquals(JsonPath.read(DOCUMENT, "$.store.foo[$.store.foo.red[0]]"), "red");
assertEquals(JsonPath.read(DOCUMENT, "$.store.book[$.store.foo.one].author"), "Evelyn Waugh");
assertThat(JsonPath.<List<String>>read(DOCUMENT, "$.store.foo[$.store.foo.bar]"), hasItems("bar"));
assertThat(JsonPath.<List<String>>read(DOCUMENT, "$..book[?(@.category==$.store.foo.category_array[0])].title"), hasItems("Sayings of the Century"));
assertThat(JsonPath.<List<String>>read(DOCUMENT, "$..book[?(@.category==$.store.foo.category)].title"), hasItems("Sayings of the Century"));
assertThat(JsonPath.<List<String>>read(DOCUMENT, "$..book[?(@['display-price'] < $.store.foo.price)].title"), hasItems("Sayings of the Century", "Moby Dick"));
}
}

Loading…
Cancel
Save