diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java index 0ee59c72..322a1719 100755 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java @@ -4,7 +4,9 @@ import com.jayway.jsonpath.JsonPathException; import com.jayway.jsonpath.Predicate; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; +import java.util.regex.Pattern; import static com.jayway.jsonpath.internal.filter.ValueNodes.PatternNode; import static com.jayway.jsonpath.internal.filter.ValueNodes.ValueListNode; @@ -256,9 +258,17 @@ public class EvaluatorFactory { } if (left.isPatternNode()) { - return matches(left.asPatternNode(), getInput(right)); + if (right.isValueListNode() || (right.isJsonNode() && right.asJsonNode().isArray(ctx))) { + return matchesAny(left.asPatternNode(), right.asJsonNode().asValueListNode(ctx)); + } else { + return matches(left.asPatternNode(), getInput(right)); + } } else { - return matches(right.asPatternNode(), getInput(left)); + if (left.isValueListNode() || (left.isJsonNode() && left.asJsonNode().isArray(ctx))) { + return matchesAny(right.asPatternNode(), left.asJsonNode().asValueListNode(ctx)); + } else { + return matches(right.asPatternNode(), getInput(left)); + } } } @@ -266,6 +276,23 @@ public class EvaluatorFactory { return patternNode.getCompiledPattern().matcher(inputToMatch).matches(); } + private boolean matchesAny(PatternNode patternNode, ValueNode valueNode) { + if (!valueNode.isValueListNode()) { + return false; + } + + ValueListNode listNode = valueNode.asValueListNode(); + Pattern pattern = patternNode.getCompiledPattern(); + + for (Iterator it = listNode.iterator(); it.hasNext(); ) { + String input = getInput(it.next()); + if (pattern.matcher(input).matches()) { + return true; + } + } + return false; + } + private String getInput(ValueNode valueNode) { String input = ""; 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 545f29c6..c7948994 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java @@ -28,7 +28,8 @@ public class FilterTest extends BaseTest { " \"char-key\" : \"c\", " + " \"arr-empty\" : [], " + " \"int-arr\" : [0,1,2,3,4], " + - " \"string-arr\" : [\"a\",\"b\",\"c\",\"d\",\"e\"] " + + " \"string-arr\" : [\"a\",\"b\",\"c\",\"d\",\"e\"], " + + " \"obj\": {\"foo\": \"bar\"}" + "}" ); @@ -263,6 +264,17 @@ public class FilterTest extends BaseTest { assertThat(filter(where("int-key").regex(Pattern.compile("^string$"))).apply(createPredicateContext(json))).isEqualTo(false); } + @Test + public void list_regex_evals() { + assertThat(filter(where("string-arr").regex(Pattern.compile("^d$"))).apply(createPredicateContext(json))).isEqualTo(true); + assertThat(filter(where("string-arr").regex(Pattern.compile("^q$"))).apply(createPredicateContext(json))).isEqualTo(false); + } + + @Test + public void obj_regex_doesnt_break() { + assertThat(filter(where("obj").regex(Pattern.compile("^foo$"))).apply(createPredicateContext(json))).isEqualTo(false); + } + //---------------------------------------------------------------------------- // // JSON equality diff --git a/json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java index 5eeb164b..b16fdd16 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java @@ -18,6 +18,47 @@ public class InlineFilterTest extends BaseTest { private static int bookCount = 4; + public static final String MULTI_STORE_JSON_DOCUMENT = "{\n" + + " \"store\" : [{\n" + + " \"name\": \"First\"," + + " \"book\" : [\n" + + " {\n" + + " \"category\" : \"reference\",\n" + + " \"author\" : \"Nigel Rees\",\n" + + " \"title\" : \"Sayings of the Century\",\n" + + " \"display-price\" : 8.95\n" + + " },\n" + + " {\n" + + " \"category\" : \"fiction\",\n" + + " \"author\" : \"Evelyn Waugh\",\n" + + " \"title\" : \"Sword of Honour\",\n" + + " \"display-price\" : 12.99\n" + + " },\n" + + " {\n" + + " \"category\" : \"fiction\",\n" + + " \"author\" : \"Herman Melville\",\n" + + " \"title\" : \"Moby Dick\",\n" + + " \"isbn\" : \"0-553-21311-3\",\n" + + " \"display-price\" : 8.99\n" + + " },\n" + + " {\n" + + " \"category\" : \"fiction\",\n" + + " \"author\" : \"J. R. R. Tolkien\",\n" + + " \"title\" : \"The Lord of the Rings\",\n" + + " \"isbn\" : \"0-395-19395-8\",\n" + + " \"display-price\" : 22.99\n" + + " }]\n" + + " },\n" + + " {\n" + + " \"name\": \"Second\",\n" + + " \"book\": [\n" + + " {\n" + + " \"category\" : \"fiction\",\n" + + " \"author\" : \"Ernest Hemmingway\",\n" + + " \"title\" : \"The Old Man and the Sea\",\n" + + " \"display-price\" : 12.99\n" + + " }]\n" + + " }]}"; private Configuration conf = Configurations.GSON_CONFIGURATION; @@ -125,6 +166,12 @@ public class InlineFilterTest extends BaseTest { assertThat(resLeft).containsExactly("Nigel Rees"); } + @Test + public void patterns_match_against_lists() { + List haveRefBooks = JsonPath.parse(MULTI_STORE_JSON_DOCUMENT).read("$.store[?(@.book[*].category =~ /Reference/i)].name"); + assertThat(haveRefBooks).containsExactly("First"); + } + @Test public void negate_exists_check() { List hasIsbn = JsonPath.parse(JSON_DOCUMENT).read("$.store.book[?(@.isbn)].author");