From ba29e7e0a187d2cb04f050492241d02aa6d1c50a Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Tue, 20 Aug 2013 13:30:55 +0200 Subject: [PATCH] Improved list filter. Updated POM files. --- README | 17 + json-path-assert/pom.xml | 2 +- json-path/pom.xml | 4 +- .../java/com/jayway/jsonpath/JsonPath.java | 9 +- .../internal/filter/ArrayEvalFilter.java | 39 ++- .../java/com/jayway/jsonpath/IssuesTest.java | 59 +++- json-path/src/test/resources/issue_24.json | 322 ++++++++++++++++++ pom.xml | 2 +- 8 files changed, 430 insertions(+), 24 deletions(-) create mode 100644 json-path/src/test/resources/issue_24.json diff --git a/README b/README index 9c9f00c3..4f0d4a97 100644 --- a/README +++ b/README @@ -6,10 +6,27 @@ Java DSL for reading and testing JSON documents. - OSGI ready - Bug fixes - Performance improvements + - select multiple attributes List> matches = JsonPath.read(DOCUMENT, "$.store.book[*].['category', 'title']"); Map match = JsonPath.read(DOCUMENT, "$.store.bicycle['color', 'display-price']"); +- Array operations and slicing improved + String JSON_ARRAY = "[1, 3, 5, 7, 8, 13, 20]"; + + JsonPath.read(JSON_ARRAY, "$[3]") => 7 //no slicing + JsonPath.read(JSON_ARRAY, "$[0,1,2]") => [1,3,5] //no slicing, multi index + JsonPath.read(JSON_ARRAY, "$[:3]") => [1,3,5] //from index 0 (inclusive) until index 3 (exclusive) + JsonPath.read(JSON_ARRAY, "$[1:5]") => [3, 5, 7, 8] //from index 1 (inclusive) until index 5 (exclusive) + JsonPath.read(JSON_ARRAY, "$[1:15]") => IndexOutOfBoundsException + JsonPath.read(JSON_ARRAY, "$[-3:]") => [8, 13, 20] //from tail grab 3 + + JsonPath.read(JSON_ARRAY, "$[3:]") => 8 //grab no 3 from tail + JsonPath.read(JSON_ARRAY, "$[(@.length -3)]") => //grab no 3 from tail (same as above) + +- improved filter on primitives. Now you can compare with @ + String json = "{\"contents\": [1,2,3]}"; + List result = JsonPath.read(json, "$.contents[?(@ == 2)]"); diff --git a/json-path-assert/pom.xml b/json-path-assert/pom.xml index f659b228..90f31315 100644 --- a/json-path-assert/pom.xml +++ b/json-path-assert/pom.xml @@ -19,7 +19,7 @@ json-path-parent com.jayway.jsonpath - 0.8.2-SNAPSHOT + 0.9.0-SNAPSHOT json-path-assert json-path-assert diff --git a/json-path/pom.xml b/json-path/pom.xml index ec3f7fda..765ad701 100644 --- a/json-path/pom.xml +++ b/json-path/pom.xml @@ -19,7 +19,7 @@ com.jayway.jsonpath json-path-parent - 0.8.2-SNAPSHOT + 0.9.0-SNAPSHOT json-path bundle @@ -32,12 +32,10 @@ net.minidev json-smart - org.apache.commons commons-lang3 - org.codehaus.jackson jackson-mapper-asl diff --git a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java index cb708788..230492bf 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java @@ -15,20 +15,21 @@ package com.jayway.jsonpath; +import com.jayway.jsonpath.internal.IOUtils; import com.jayway.jsonpath.internal.PathToken; import com.jayway.jsonpath.internal.PathTokenizer; -import com.jayway.jsonpath.internal.IOUtils; import com.jayway.jsonpath.internal.filter.PathTokenFilter; import com.jayway.jsonpath.spi.HttpProviderFactory; import com.jayway.jsonpath.spi.JsonProvider; import com.jayway.jsonpath.spi.JsonProviderFactory; import org.apache.commons.lang3.StringUtils; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.util.LinkedList; -import java.util.List; -import java.util.Map; import java.util.regex.Pattern; import static java.util.Arrays.asList; diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java index d72fb00f..eb00d0fd 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java @@ -41,15 +41,22 @@ public class ArrayEvalFilter extends PathTokenFilter { trimmedCondition = trimmedCondition.replace("['", "."); trimmedCondition = trimmedCondition.replace("']", ""); } - - trimmedCondition = trim(trimmedCondition, 5, 2); - + if(trimmedCondition.startsWith("[?(@==")){ + trimmedCondition = trim(trimmedCondition, 4, 2); + } else { + trimmedCondition = trim(trimmedCondition, 5, 2); + } this.conditionStatement = createConditionStatement(trimmedCondition); } @Override public Object filter(Object obj, JsonProvider jsonProvider) { - List src = jsonProvider.toList(obj); + List src = null; + try { + src = jsonProvider.toList(obj); + } catch (ClassCastException e){ + throw new InvalidPathException("The path fragment '" + this.condition + "' can not be applied to a JSON object only a JSON array.", e); + } List result = jsonProvider.createList(); for (Object item : src) { @@ -71,21 +78,25 @@ public class ArrayEvalFilter extends PathTokenFilter { } private boolean isMatch(Object check, ConditionStatement conditionStatement, JsonProvider jsonProvider) { - if (!jsonProvider.isMap(check)) { - return false; - } - Map obj = jsonProvider.toMap(check); + if (jsonProvider.isMap(check)) { + Map obj = jsonProvider.toMap(check); - if (!obj.containsKey(conditionStatement.getField())) { - return false; - } + if (!obj.containsKey(conditionStatement.getField())) { + return false; + } - Object propertyValue = obj.get(conditionStatement.getField()); + Object propertyValue = obj.get(conditionStatement.getField()); - if (jsonProvider.isContainer(propertyValue)) { + if (jsonProvider.isContainer(propertyValue)) { + return false; + } + return ExpressionEvaluator.eval(propertyValue, conditionStatement.getOperator(), conditionStatement.getExpected()); + } else if(jsonProvider.isList(check)) { return false; + } else { + return ExpressionEvaluator.eval(check, conditionStatement.getOperator(), conditionStatement.getExpected()); } - return ExpressionEvaluator.eval(propertyValue, conditionStatement.getOperator(), conditionStatement.getExpected()); + } diff --git a/json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java b/json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java index fbf5b925..7fe139d4 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java @@ -1,8 +1,11 @@ package com.jayway.jsonpath; +import com.jayway.jsonpath.internal.IOUtils; import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Test; +import java.io.InputStream; import java.util.List; import java.util.regex.Matcher; @@ -68,11 +71,65 @@ public class IssuesTest { @Test + public void issue_24(){ + + InputStream is = null; + try { + is = this.getClass().getResourceAsStream("/issue_24.json"); + + + //Object o = JsonPath.read(is, "$.project[?(@.template.@key == 'foo')].field[*].@key"); + Object o = JsonPath.read(is, "$.project.field[*].@key"); + //Object o = JsonPath.read(is, "$.project.template[?(@.@key == 'foo')].field[*].@key"); + + System.out.println(o); + + is.close(); + } catch (Exception e){ + e.printStackTrace(); + IOUtils.closeQuietly(is); + } + + } + + @Test + public void issue_28_string(){ + String json = "{\"contents\": [\"one\",\"two\",\"three\"]}"; + + List result = JsonPath.read(json, "$.contents[?(@ == 'two')]"); + + assertThat(result, Matchers.contains("two")); + assertEquals(1, result.size()); + } + + @Test + public void issue_28_int(){ + String json = "{\"contents\": [1,2,3]}"; + + List result = JsonPath.read(json, "$.contents[?(@ == 2)]"); + + assertThat(result, Matchers.contains(2)); + assertEquals(1, result.size()); + } + + @Test + public void issue_28_boolean(){ + String json = "{\"contents\": [true, true, false]}"; + + List result = JsonPath.read(json, "$.contents[?(@ == true)]"); + + assertThat(result, Matchers.contains(true, true)); + assertEquals(2, result.size()); + } + + + + @Test public void issue_22() throws Exception { String json = "{\"a\":[{\"b\":1,\"c\":2},{\"b\":5,\"c\":2}]}"; System.out.println(JsonPath.read(json, "a[?(@.b==5)].d")); } - + @Test public void issue_29_b() throws Exception { String json = "{\"list\": [ { \"a\":\"atext\", \"b\":{ \"b-a\":\"batext\", \"b-b\":\"bbtext\" } }, { \"a\":\"atext2\", \"b\":{ \"b-a\":\"batext2\", \"b-b\":\"bbtext2\" } } ] }"; diff --git a/json-path/src/test/resources/issue_24.json b/json-path/src/test/resources/issue_24.json new file mode 100644 index 00000000..5e551608 --- /dev/null +++ b/json-path/src/test/resources/issue_24.json @@ -0,0 +1,322 @@ +{ + "project": { + "@key": "Signaturengruppe ars.hydr.", + "template": [ + { + "@key": "foo", + "collection": [ + "Autobiographica", + "DigiWunschbuch", + "Itineraria", + "Manuscriptae", + "Maps", + "Mathematica", + "Nordamericana", + "Wissenschaftsgeschichte", + "Sibirica", + "Varia", + "Zoologica" + ] + }, + { + "@key": "Digitalisierungsprojekt_ars_hydr", + "collection": [ + "Autobiographica", + "DigiWunschbuch", + "Itineraria", + "Manuscriptae", + "Maps", + "Mathematica", + "Nordamericana", + "Wissenschaftsgeschichte", + "Sibirica", + "Varia", + "Zoologica" + ] + } + ], + "field": [ + { + "@key": "Artist", + "required": "false", + "source": "werk", + "option": [ + { + "@label": "Nieders?chsische Staats- und Universit?tsbibliothek G?ttingen, Germany", + "$": "SUB" + }, + { + "@label": "DIGIZEITSCHRIFTEN e.V., Nieders?chsische Staats- und Universit?tsbibliothek G?ttingen, Germany", + "$": "DIGIZEIT" + } + ], + "ughbinding": "false" + }, + { + "@key": "Schrifttyp", + "required": "false", + "source": "werk", + "option": [ + { + "@label": "gemischt", + "$": "gemischt" + }, + { + "@label": "Fraktur", + "$": "Fraktur" + }, + { + "@label": "Antiqua", + "$": "Antiqua" + } + ], + "ughbinding": "false" + }, + { + "@key": "Titel", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "Titel (Sortierung)", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "Titel", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "Titel (Sortierung)", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "Autoren", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "ATS", + "required": "false", + "source": "werk", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "TSL", + "required": "false", + "source": "werk", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "PPN analog c-Satz", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "PPN digital c-Satz", + "required": "true", + "source": "werk", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "PPN analog a-Satz", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "PPN digital a-Satz", + "required": "true", + "source": "werk", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "PPN analog b-Satz", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "PPN digital b-Satz", + "required": "true", + "source": "werk", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "ISSN", + "required": "true", + "source": "werk", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "PPN analog Band", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "PPN digital Band", + "required": "true", + "source": "werk", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "Titel (Band)", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "Titel (Band) (Sortierung)", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "Autoren (Band)", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "Bandnummer", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "Nummer (Sortierung)", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "Nummer (Benennung)", + "required": "true", + "source": "vorlage", + "ughbinding": "false" + }, + { + "@key": "PPN analog f-Satz", + "required": "true", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "PPN digital f-Satz", + "required": "true", + "source": "werk", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "Erscheinungsort", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "Erscheinungsjahr", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "Erscheinungsjahr", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "Verlag", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "firstchild" + }, + { + "@key": "Verlag", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "topstruct" + }, + { + "@key": "Signatur", + "required": "false", + "source": "vorlage", + "ughbinding": "true", + "insertionLevel": "boundbook" + }, + { + "@key": "Farbtiefe", + "required": "true", + "source": "werk", + "option": [ + { + "@label": "Bitonal", + "$": "Bitonal" + }, + { + "@label": "Farbe", + "$": "Farbe" + }, + { + "@label": "Graustufen", + "$": "Graustufen" + } + ], + "ughbinding": "false" + }, + { + "@key": "?ffnungswinkel", + "required": "true", + "source": "werk", + "option": [ + { + "@label": "180?", + "$": "180?" + }, + { + "@label": "90?", + "$": "90?" + } + ], + "ughbinding": "false" + } + ] + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8614e6f5..fd1b58da 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ com.jayway.jsonpath json-path-parent pom - 0.8.2-SNAPSHOT + 0.9.0-SNAPSHOT https://github.com/jayway/JsonPath json-path-parent-pom Java JsonPath implementation