Browse Source

Support for regex in inline filters.

pull/60/head
Kalle Stenflo 10 years ago
parent
commit
78c8d908c1
  1. 6
      changelog.md
  2. 49
      json-path/src/main/java/com/jayway/jsonpath/Criteria.java
  3. 20
      json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java

6
changelog.md

@ -10,6 +10,12 @@ In The Pipe
`parse(JSON_DOCUMENT).put("$.store.book[1]", "new-key", "new-val")` `parse(JSON_DOCUMENT).put("$.store.book[1]", "new-key", "new-val")`
`parse(JSON_DOCUMENT).add("$.store.book", newBook)` `parse(JSON_DOCUMENT).add("$.store.book", newBook)`
`parse(JSON_DOCUMENT).delete("$.store.book[1].display-price")` `parse(JSON_DOCUMENT).delete("$.store.book[1].display-price")`
* Support regex in inline filters (ruby syntax)
`parse(JSON_DOCUMENT).read("$.store.book[?(@.category =~ /reference/)].author")`
`parse(JSON_DOCUMENT).read("$.store.book[?(@.category =~ /REFERENCE/i)].author")`
* Inline filter does not force path first
`parse(JSON_DOCUMENT).read("$.store.book[?(@.category == 'reference')].author")`
`parse(JSON_DOCUMENT).read("$.store.book[?('reference' == @.category)].author")`
1.1.0 (2014-10-01) 1.1.0 (2014-10-01)

49
json-path/src/main/java/com/jayway/jsonpath/Criteria.java

@ -45,7 +45,8 @@ public class Criteria implements Predicate {
CriteriaType.LTE.toString(), CriteriaType.LTE.toString(),
CriteriaType.NE.toString(), CriteriaType.NE.toString(),
CriteriaType.LT.toString(), CriteriaType.LT.toString(),
CriteriaType.GT.toString() CriteriaType.GT.toString(),
CriteriaType.REGEX.toString()
}; };
private Object left; private Object left;
@ -232,13 +233,27 @@ public class Criteria implements Predicate {
@Override @Override
boolean eval(Object left, Object right, PredicateContext ctx) { boolean eval(Object left, Object right, PredicateContext ctx) {
boolean res = false; boolean res = false;
final Pattern pattern = (Pattern) left; Pattern pattern;
if (right != null && right instanceof String) { Object target;
res = pattern.matcher(right.toString()).matches();
if(right instanceof Pattern){
pattern = (Pattern) right;
target = left;
} else {
pattern = (Pattern) left;
target = right;
}
if(target != null){
res = pattern.matcher(target.toString()).matches();
} }
if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right, name(), left.toString(), res); if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right.toString(), name(), left.toString(), res);
return res; return res;
} }
@Override
public String toString() {
return "=~";
}
}, },
MATCHES { MATCHES {
@Override @Override
@ -282,6 +297,8 @@ public class Criteria implements Predicate {
return LTE; return LTE;
} else if ("!=".equals(str)) { } else if ("!=".equals(str)) {
return NE; return NE;
} else if ("=~".equals(str)) {
return REGEX;
} else { } else {
throw new UnsupportedOperationException("CriteriaType " + str + " can not be parsed"); throw new UnsupportedOperationException("CriteriaType " + str + " can not be parsed");
} }
@ -639,9 +656,27 @@ public class Criteria implements Predicate {
private static boolean isPath(String string){ private static boolean isPath(String string){
return (string != null && (string.startsWith("$") || string.startsWith("@"))); return (string != null && (string.startsWith("$") || string.startsWith("@")));
} }
private static boolean isString(String string){ private static boolean isString(String string){
return (string != null && !string.isEmpty() && string.charAt(0) == '\'' && string.charAt(string.length() - 1) == '\''); return (string != null && !string.isEmpty() && string.charAt(0) == '\'' && string.charAt(string.length() - 1) == '\'');
} }
private static boolean isPattern(String string){
return (string != null
&& !string.isEmpty()
&& string.charAt(0) == '/'
&& (string.charAt(string.length() - 1) == '/' || (string.charAt(string.length() - 2) == '/' && string.charAt(string.length() - 1) == 'i'))
);
}
private static Pattern compilePattern(String string) {
int lastIndex = string.lastIndexOf('/');
boolean ignoreCase = string.endsWith("i");
String regex = string.substring(1, lastIndex);
int flags = ignoreCase ? Pattern.CASE_INSENSITIVE : 0;
return Pattern.compile(regex, flags);
}
/** /**
@ -691,6 +726,8 @@ public class Criteria implements Predicate {
leftPrepared = leftPath; leftPrepared = leftPath;
} else if(isString(left)) { } else if(isString(left)) {
leftPrepared = left.substring(1, left.length() - 1); leftPrepared = left.substring(1, left.length() - 1);
} else if(isPattern(left)){
leftPrepared = compilePattern(left);
} }
if(isPath(right)){ if(isPath(right)){
@ -701,6 +738,8 @@ public class Criteria implements Predicate {
rightPrepared = rightPath; rightPrepared = rightPath;
} else if(isString(right)) { } else if(isString(right)) {
rightPrepared = right.substring(1, right.length() - 1); rightPrepared = right.substring(1, right.length() - 1);
} else if(isPattern(right)){
rightPrepared = compilePattern(right);
} }
if(leftPath != null && operator.isEmpty()){ if(leftPath != null && operator.isEmpty()){

20
json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java

@ -109,4 +109,24 @@ public class InlineFilterTest extends BaseTest {
assertThat(res).containsExactly("Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"); assertThat(res).containsExactly("Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien");
} }
@Test
public void patterns_can_be_evaluated() {
List<String> resLeft = JsonPath.parse(JSON_DOCUMENT).read("$.store.book[?(@.category =~ /reference/)].author");
assertThat(resLeft).containsExactly("Nigel Rees");
resLeft = JsonPath.parse(JSON_DOCUMENT).read("$.store.book[?(/reference/ =~ @.category)].author");
assertThat(resLeft).containsExactly("Nigel Rees");
}
@Test
public void patterns_can_be_evaluated_with_ignore_case() {
List<String> resLeft = JsonPath.parse(JSON_DOCUMENT).read("$.store.book[?(@.category =~ /REFERENCE/)].author");
assertThat(resLeft).isEmpty();
resLeft = JsonPath.parse(JSON_DOCUMENT).read("$.store.book[?(@.category =~ /REFERENCE/i)].author");
assertThat(resLeft).containsExactly("Nigel Rees");
}
} }

Loading…
Cancel
Save