Skip to content

Commit 3f4900d

Browse files
MorganEPatchMorgan Patch
and
Morgan Patch
authored
Allow a list to be compared to a regex in a filter. (#685)
Co-authored-by: Morgan Patch <[email protected]>
1 parent 2e6b43e commit 3f4900d

File tree

3 files changed

+89
-3
lines changed

3 files changed

+89
-3
lines changed

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

+29-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import com.jayway.jsonpath.Predicate;
55

66
import java.util.HashMap;
7+
import java.util.Iterator;
78
import java.util.Map;
9+
import java.util.regex.Pattern;
810

911
import static com.jayway.jsonpath.internal.filter.ValueNodes.PatternNode;
1012
import static com.jayway.jsonpath.internal.filter.ValueNodes.ValueListNode;
@@ -256,16 +258,41 @@ public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateCont
256258
}
257259

258260
if (left.isPatternNode()) {
259-
return matches(left.asPatternNode(), getInput(right));
261+
if (right.isValueListNode() || (right.isJsonNode() && right.asJsonNode().isArray(ctx))) {
262+
return matchesAny(left.asPatternNode(), right.asJsonNode().asValueListNode(ctx));
263+
} else {
264+
return matches(left.asPatternNode(), getInput(right));
265+
}
260266
} else {
261-
return matches(right.asPatternNode(), getInput(left));
267+
if (left.isValueListNode() || (left.isJsonNode() && left.asJsonNode().isArray(ctx))) {
268+
return matchesAny(right.asPatternNode(), left.asJsonNode().asValueListNode(ctx));
269+
} else {
270+
return matches(right.asPatternNode(), getInput(left));
271+
}
262272
}
263273
}
264274

265275
private boolean matches(PatternNode patternNode, String inputToMatch) {
266276
return patternNode.getCompiledPattern().matcher(inputToMatch).matches();
267277
}
268278

279+
private boolean matchesAny(PatternNode patternNode, ValueNode valueNode) {
280+
if (!valueNode.isValueListNode()) {
281+
return false;
282+
}
283+
284+
ValueListNode listNode = valueNode.asValueListNode();
285+
Pattern pattern = patternNode.getCompiledPattern();
286+
287+
for (Iterator<ValueNode> it = listNode.iterator(); it.hasNext(); ) {
288+
String input = getInput(it.next());
289+
if (pattern.matcher(input).matches()) {
290+
return true;
291+
}
292+
}
293+
return false;
294+
}
295+
269296
private String getInput(ValueNode valueNode) {
270297
String input = "";
271298

json-path/src/test/java/com/jayway/jsonpath/FilterTest.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ public class FilterTest extends BaseTest {
2828
" \"char-key\" : \"c\", " +
2929
" \"arr-empty\" : [], " +
3030
" \"int-arr\" : [0,1,2,3,4], " +
31-
" \"string-arr\" : [\"a\",\"b\",\"c\",\"d\",\"e\"] " +
31+
" \"string-arr\" : [\"a\",\"b\",\"c\",\"d\",\"e\"], " +
32+
" \"obj\": {\"foo\": \"bar\"}" +
3233
"}"
3334
);
3435

@@ -263,6 +264,17 @@ public void string_regex_evals() {
263264
assertThat(filter(where("int-key").regex(Pattern.compile("^string$"))).apply(createPredicateContext(json))).isEqualTo(false);
264265
}
265266

267+
@Test
268+
public void list_regex_evals() {
269+
assertThat(filter(where("string-arr").regex(Pattern.compile("^d$"))).apply(createPredicateContext(json))).isEqualTo(true);
270+
assertThat(filter(where("string-arr").regex(Pattern.compile("^q$"))).apply(createPredicateContext(json))).isEqualTo(false);
271+
}
272+
273+
@Test
274+
public void obj_regex_doesnt_break() {
275+
assertThat(filter(where("obj").regex(Pattern.compile("^foo$"))).apply(createPredicateContext(json))).isEqualTo(false);
276+
}
277+
266278
//----------------------------------------------------------------------------
267279
//
268280
// JSON equality

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

+47
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,47 @@ public class InlineFilterTest extends BaseTest {
1818

1919
private static int bookCount = 4;
2020

21+
public static final String MULTI_STORE_JSON_DOCUMENT = "{\n" +
22+
" \"store\" : [{\n" +
23+
" \"name\": \"First\"," +
24+
" \"book\" : [\n" +
25+
" {\n" +
26+
" \"category\" : \"reference\",\n" +
27+
" \"author\" : \"Nigel Rees\",\n" +
28+
" \"title\" : \"Sayings of the Century\",\n" +
29+
" \"display-price\" : 8.95\n" +
30+
" },\n" +
31+
" {\n" +
32+
" \"category\" : \"fiction\",\n" +
33+
" \"author\" : \"Evelyn Waugh\",\n" +
34+
" \"title\" : \"Sword of Honour\",\n" +
35+
" \"display-price\" : 12.99\n" +
36+
" },\n" +
37+
" {\n" +
38+
" \"category\" : \"fiction\",\n" +
39+
" \"author\" : \"Herman Melville\",\n" +
40+
" \"title\" : \"Moby Dick\",\n" +
41+
" \"isbn\" : \"0-553-21311-3\",\n" +
42+
" \"display-price\" : 8.99\n" +
43+
" },\n" +
44+
" {\n" +
45+
" \"category\" : \"fiction\",\n" +
46+
" \"author\" : \"J. R. R. Tolkien\",\n" +
47+
" \"title\" : \"The Lord of the Rings\",\n" +
48+
" \"isbn\" : \"0-395-19395-8\",\n" +
49+
" \"display-price\" : 22.99\n" +
50+
" }]\n" +
51+
" },\n" +
52+
" {\n" +
53+
" \"name\": \"Second\",\n" +
54+
" \"book\": [\n" +
55+
" {\n" +
56+
" \"category\" : \"fiction\",\n" +
57+
" \"author\" : \"Ernest Hemmingway\",\n" +
58+
" \"title\" : \"The Old Man and the Sea\",\n" +
59+
" \"display-price\" : 12.99\n" +
60+
" }]\n" +
61+
" }]}";
2162

2263
private Configuration conf = Configurations.GSON_CONFIGURATION;
2364

@@ -125,6 +166,12 @@ public void patterns_can_be_evaluated_with_ignore_case() {
125166
assertThat(resLeft).containsExactly("Nigel Rees");
126167
}
127168

169+
@Test
170+
public void patterns_match_against_lists() {
171+
List<String> haveRefBooks = JsonPath.parse(MULTI_STORE_JSON_DOCUMENT).read("$.store[?(@.book[*].category =~ /Reference/i)].name");
172+
assertThat(haveRefBooks).containsExactly("First");
173+
}
174+
128175
@Test
129176
public void negate_exists_check() {
130177
List<String> hasIsbn = JsonPath.parse(JSON_DOCUMENT).read("$.store.book[?(@.isbn)].author");

0 commit comments

Comments
 (0)