diff --git a/json-assert/src/main/java/com/jayway/jsonassert/JsonPath.java b/json-assert/src/main/java/com/jayway/jsonassert/JsonPath.java index aa189531..dcb0319c 100644 --- a/json-assert/src/main/java/com/jayway/jsonassert/JsonPath.java +++ b/json-assert/src/main/java/com/jayway/jsonassert/JsonPath.java @@ -10,6 +10,11 @@ import java.util.Map; */ public interface JsonPath { + public enum ResultType { + PATH, + JSON + } + /** * Get a new reader with the given path as root * diff --git a/json-assert/src/main/java/com/jayway/jsonpath/JsonPath.java b/json-assert/src/main/java/com/jayway/jsonpath/JsonPath.java new file mode 100644 index 00000000..3f89e115 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/JsonPath.java @@ -0,0 +1,83 @@ +package com.jayway.jsonpath; + + +import com.jayway.jsonpath.filter.JsonPathFilterChain; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.List; + +import static java.lang.String.format; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 1:03 PM + */ +public class JsonPath { + + private static final JSONParser JSON_PARSER = new JSONParser(); + + private JsonPathFilterChain filters; + + public static JsonPath compile(String jsonPath) { + return new JsonPath(jsonPath); + } + + + private JsonPath(String jsonPath) { + this.filters = new JsonPathFilterChain(PathUtil.splitPath(jsonPath)); + } + + public List read(Object json) { + return (List) filters.filter(json); + } + + public List read(String json) throws java.text.ParseException { + Object root = null; + try { + root = JSON_PARSER.parse(json); + } catch (ParseException e) { + throw new java.text.ParseException(json, e.getPosition()); + } + return (List) filters.filter(root); + } + + + public static List read(String json, String jsonPath) throws java.text.ParseException { + JsonPath path = compile(jsonPath); + + return path.read(json); + } + + public static List read(Object json, String jsonPath) throws java.text.ParseException { + JsonPath path = compile(jsonPath); + + return path.read(json); + } + + public static T readOne(String json, String jsonPath) throws java.text.ParseException { + JsonPath path = compile(jsonPath); + + List result = read(json, jsonPath); + + if (result.size() != 1) { + throw new RuntimeException(format("Expected one result when reading path: %s but was: ", jsonPath, result.size())); + } + + return (T) result.get(0); + } + + public static T readOne(Object json, String jsonPath) throws java.text.ParseException { + JsonPath path = compile(jsonPath); + + List result = read(json, jsonPath); + + if (result.size() != 1) { + throw new RuntimeException(format("Expected one result when reading path: %s but was: ", jsonPath, result.size())); + } + + return (T) result.get(0); + } +} diff --git a/json-assert/src/main/java/com/jayway/jsonpath/PathItem.java b/json-assert/src/main/java/com/jayway/jsonpath/PathItem.java new file mode 100644 index 00000000..1a2b71d9 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/PathItem.java @@ -0,0 +1,32 @@ +package com.jayway.jsonpath; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 2:33 PM + */ +public class PathItem { + + private final String path; + + private final Object target; + + public PathItem(String path, Object target) { + this.path = path; + this.target = target; + } + + public String getPath() { + return path; + } + + public Object getTarget() { + return target; + } + + +} diff --git a/json-assert/src/main/java/com/jayway/jsonpath/PathUtil.java b/json-assert/src/main/java/com/jayway/jsonpath/PathUtil.java new file mode 100644 index 00000000..c83be718 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/PathUtil.java @@ -0,0 +1,60 @@ +package com.jayway.jsonpath; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import java.util.LinkedList; +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 2:08 PM + */ +public class PathUtil { + + public static boolean isContainer(Object obj) { + return (isArray(obj) || isDocument(obj)); + } + + public static boolean isArray(Object obj) { + return (obj instanceof JSONArray); + } + + public static boolean isDocument(Object obj) { + return (obj instanceof JSONObject); + } + + public static JSONArray toArray(Object array) { + return (JSONArray) array; + } + + public static JSONObject toDocument(Object document) { + return (JSONObject) document; + } + + + public static List splitPath(String jsonPath) { + + LinkedList fragments = new LinkedList(); + + if (!jsonPath.startsWith("$.")) { + jsonPath = "$." + jsonPath; + } + + jsonPath = jsonPath.replace("..", ".~.") + .replace("[", ".[") + .replace("@.", "@"); + + String[] split = jsonPath.split("\\."); + + for (int i = 0; i < split.length; i++) { + if(split[i].trim().isEmpty()){ + continue; + } + fragments.add(split[i].replace("@", "@.").replace("~", "..")); + } + return fragments; + } +} diff --git a/json-assert/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterBase.java b/json-assert/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterBase.java new file mode 100644 index 00000000..e85de518 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterBase.java @@ -0,0 +1,24 @@ +package com.jayway.jsonpath.filter; + +import com.jayway.jsonpath.PathItem; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import java.util.Collection; +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 2:01 PM + */ +public abstract class JsonPathFilterBase { + + + + + public abstract List apply(List filter); + + +} diff --git a/json-assert/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterChain.java b/json-assert/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterChain.java new file mode 100644 index 00000000..f0c5cfe6 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterChain.java @@ -0,0 +1,47 @@ +package com.jayway.jsonpath.filter; + +import org.json.simple.JSONArray; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * User: kallestenflo + * Date: 2/2/11 + * Time: 2:00 PM + */ +public class JsonPathFilterChain { + + private static final List EMPTY_LIST = Collections.unmodifiableList(new JSONArray()); + + private List filters; + + public JsonPathFilterChain(List pathFragments) { + filters = configureFilters(pathFragments); + } + + private List configureFilters(List pathFragments) { + + List configured = new LinkedList(); + + for (String pathFragment : pathFragments) { + configured.add(JsonPathFilterFactory.createFilter(pathFragment)); + } + return configured; + } + + public List filter(Object root) { + + List rootList = new JSONArray(); + rootList.add(root); + + List result = rootList; + + for (JsonPathFilterBase filter : filters) { + result = filter.apply(result); + } + + return result; + } +} diff --git a/json-assert/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterFactory.java b/json-assert/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterFactory.java new file mode 100644 index 00000000..705dcb47 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterFactory.java @@ -0,0 +1,37 @@ +package com.jayway.jsonpath.filter; + +import java.util.regex.Pattern; + +/** + * User: kallestenflo + * Date: 2/2/11 + * Time: 2:03 PM + */ +public class JsonPathFilterFactory { + + private static final Pattern ROOT_FILTER = Pattern.compile("\\$"); + private static final Pattern PROPERTY_FILTER = Pattern.compile("\\w+"); + private static final Pattern WILDCARD_PROPERTY_FILTER = Pattern.compile("\\*"); + private static final Pattern LIST_FILTER = Pattern.compile("\\[.*?\\]"); + private static final Pattern TRAVERSE_FILTER = Pattern.compile("\\.\\."); + + public static JsonPathFilterBase createFilter(String pathFragment){ + + + if(ROOT_FILTER.matcher(pathFragment).matches()){ + return new RootFilter(); + } + else if(PROPERTY_FILTER.matcher(pathFragment).matches() || WILDCARD_PROPERTY_FILTER.matcher(pathFragment).matches() ){ + return new PropertyFilter(pathFragment); + } + else if(LIST_FILTER.matcher(pathFragment).matches()){ + return new ListFilter(pathFragment); + } + else if(TRAVERSE_FILTER.matcher(pathFragment).matches()){ + return new TraverseFilter(pathFragment); + } + + return null; + } + +} diff --git a/json-assert/src/main/java/com/jayway/jsonpath/filter/ListFilter.java b/json-assert/src/main/java/com/jayway/jsonpath/filter/ListFilter.java new file mode 100644 index 00000000..7227de35 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/filter/ListFilter.java @@ -0,0 +1,177 @@ +package com.jayway.jsonpath.filter; + +import com.jayway.jsonpath.PathUtil; +import org.json.simple.JSONArray; + +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 2:32 PM + */ +public class ListFilter extends JsonPathFilterBase { + + private static final Pattern LIST_INDEX_PATTERN = Pattern.compile("\\[(\\s?\\d+\\s?,?)+\\]"); + private static final Pattern LIST_PULL_PATTERN = Pattern.compile("\\[\\s?:(\\d+)\\s?\\]"); //[ :2 ] + private static final Pattern LIST_WILDCARD_PATTERN = Pattern.compile("\\[\\*\\]"); + private static final Pattern LIST_TAIL_PATTERN_SHORT = Pattern.compile("\\[\\s*-\\s*(\\d+):\\s*\\]"); // [(@.length - 12)] OR [-13:] + private static final Pattern LIST_TAIL_PATTERN_LONG = Pattern.compile("\\[\\s*\\(\\s*@\\.length\\s*-\\s*(\\d+)\\s*\\)\\s*\\]"); + private static final Pattern LIST_TAIL_PATTERN = Pattern.compile("(" + LIST_TAIL_PATTERN_SHORT.pattern() + "|" + LIST_TAIL_PATTERN_LONG.pattern() + ")"); + private static final Pattern LIST_ITEM_HAS_PROPERTY_PATTERN = Pattern.compile("\\[\\s?\\?\\s?\\(\\s?@\\.(\\w+)\\s?\\)\\s?\\]"); + + private final String pathFragment; + + public ListFilter(String pathFragment) { + this.pathFragment = pathFragment; + } + + @Override + public List apply(List items) { + List result = new JSONArray(); + + if (LIST_INDEX_PATTERN.matcher(pathFragment).matches()) { + return filterByListIndex(items); + } else if (LIST_WILDCARD_PATTERN.matcher(pathFragment).matches()) { + return filterByWildcard(items); + } else if (LIST_TAIL_PATTERN.matcher(pathFragment).matches()) { + return filterByListTailIndex(items); + } else if (LIST_PULL_PATTERN.matcher(pathFragment).matches()) { + return filterByPullIndex(items); + } else if (LIST_ITEM_HAS_PROPERTY_PATTERN.matcher(pathFragment).matches()){ + return filterByItemProperty(items); + } + + return result; + } + + private List filterByItemProperty(List items) { + List result = new JSONArray(); + + String prop = getFilterProperty(); + + for (Object current : items) { + for (Object item : PathUtil.toArray(current)) { + + if(PathUtil.isDocument(item)){ + if(PathUtil.toDocument(item).containsKey(prop)) { + result.add(item); + } + } + } + } + return result; + } + + + private List filterByWildcard(List items) { + List result = new JSONArray(); + + for (Object current : items) { + result.addAll(PathUtil.toArray(current)); + } + return result; + } + + private List filterByListTailIndex(List items) { + List result = new JSONArray(); + + + for (Object current : items) { + List array = PathUtil.toArray(current); + result.add(array.get(getTailIndex(array.size()))); + } + return result; + } + + private List filterByListIndex(List items) { + List result = new JSONArray(); + + for (Object current : items) { + Integer[] index = getArrayIndex(); + for (int i : index) { + + result.add(PathUtil.toArray(current).get(i)); + } + } + return result; + } + + private List filterByPullIndex(List items) { + List result = new JSONArray(); + + for (Object current : items) { + Integer[] index = getListPullIndex(); + for (int i : index) { + + result.add(PathUtil.toArray(current).get(i)); + } + } + return result; + } + + private String getFilterProperty(){ + Matcher matcher = LIST_ITEM_HAS_PROPERTY_PATTERN.matcher(pathFragment); + if (matcher.matches()) { + return matcher.group(1); + } + throw new IllegalArgumentException("invalid list filter property"); + } + + private int getTailIndex(int arraySize) { + + Matcher matcher = LIST_TAIL_PATTERN_SHORT.matcher(pathFragment); + if (matcher.matches()) { + + int index = Integer.parseInt(matcher.group(1)); + + return arraySize - index; + } + matcher = LIST_TAIL_PATTERN_LONG.matcher(pathFragment); + if (matcher.matches()) { + + int index = Integer.parseInt(matcher.group(1)); + + return arraySize - index; + } + + throw new IllegalArgumentException("invalid list index"); + + } + + private Integer[] getListPullIndex() { + Matcher matcher = LIST_PULL_PATTERN.matcher(pathFragment); + if (matcher.matches()) { + + int pullCount = Integer.parseInt(matcher.group(1)); + + List result = new LinkedList(); + + for (int y = 0; y < pullCount; y++) { + result.add(y); + } + return result.toArray(new Integer[0]); + } + throw new IllegalArgumentException("invalid list index"); + } + + private Integer[] getArrayIndex() { + + String prepared = pathFragment.replaceAll(" ", ""); + prepared = prepared.substring(1, prepared.length() - 1); + + List index = new LinkedList(); + + String[] split = prepared.split(","); + + for (String s : split) { + index.add(Integer.parseInt(s)); + } + return index.toArray(new Integer[0]); + } + +} \ No newline at end of file diff --git a/json-assert/src/main/java/com/jayway/jsonpath/filter/PropertyFilter.java b/json-assert/src/main/java/com/jayway/jsonpath/filter/PropertyFilter.java new file mode 100644 index 00000000..da248a34 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/filter/PropertyFilter.java @@ -0,0 +1,41 @@ +package com.jayway.jsonpath.filter; + +import com.jayway.jsonpath.PathUtil; +import org.json.simple.JSONArray; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 2:32 PM + */ +public class PropertyFilter extends JsonPathFilterBase { + private final String pathFragment; + + public PropertyFilter(String pathFragment) { + this.pathFragment = pathFragment; + } + + @Override + public List apply(List filter) { + List result = new JSONArray(); + + for (Object current : filter) { + + if ("*".equals(pathFragment)) { + + for (Object value : PathUtil.toDocument(current).values()) { + result.add(value); + } + + } else { + if (PathUtil.toDocument(current).containsKey(pathFragment)) { + result.add(PathUtil.toDocument(current).get(pathFragment)); + } + } + } + return result; + } +} diff --git a/json-assert/src/main/java/com/jayway/jsonpath/filter/RootFilter.java b/json-assert/src/main/java/com/jayway/jsonpath/filter/RootFilter.java new file mode 100644 index 00000000..a7e138b4 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/filter/RootFilter.java @@ -0,0 +1,17 @@ +package com.jayway.jsonpath.filter; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 2:31 PM + */ +public class RootFilter extends JsonPathFilterBase{ + + @Override + public List apply(List filter) { + return filter; + } +} diff --git a/json-assert/src/main/java/com/jayway/jsonpath/filter/TraverseFilter.java b/json-assert/src/main/java/com/jayway/jsonpath/filter/TraverseFilter.java new file mode 100644 index 00000000..220df3e8 --- /dev/null +++ b/json-assert/src/main/java/com/jayway/jsonpath/filter/TraverseFilter.java @@ -0,0 +1,50 @@ +package com.jayway.jsonpath.filter; + +import com.jayway.jsonpath.PathUtil; +import org.json.simple.JSONArray; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 2:33 PM + */ +public class TraverseFilter extends JsonPathFilterBase { + private final String pathFragment; + + public TraverseFilter(String pathFragment) { + this.pathFragment = pathFragment; + } + + @Override + public List apply(List filter) { + List result = new JSONArray(); + + traverse(filter, result); + + return result; + } + + private void traverse(Object container, List result) { + + if (PathUtil.isDocument(container)) { + result.add(container); + + for (Object value : PathUtil.toDocument(container).values()) { + if (PathUtil.isContainer(value)) { + traverse(value, result); + } + } + } else if (PathUtil.isArray(container)) { + + for (Object value : PathUtil.toArray(container)) { + if (PathUtil.isContainer(value)) { + traverse(value, result); + } + } + } + } + +} \ No newline at end of file diff --git a/json-assert/src/test/java/com/jayway/jsonpath/JsonPathTest.java b/json-assert/src/test/java/com/jayway/jsonpath/JsonPathTest.java new file mode 100644 index 00000000..c61e6261 --- /dev/null +++ b/json-assert/src/test/java/com/jayway/jsonpath/JsonPathTest.java @@ -0,0 +1,150 @@ +package com.jayway.jsonpath; + +import org.apache.commons.lang.StringUtils; +import org.junit.Test; + +import java.util.List; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItems; +import static org.junit.Assert.*; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 3:07 PM + */ +public class JsonPathTest { + + public final static String DOCUMENT = + "{ \"store\": {\n" + + " \"book\": [ \n" + + " { \"category\": \"reference\",\n" + + " \"author\": \"Nigel Rees\",\n" + + " \"title\": \"Sayings of the Century\",\n" + + " \"price\": 8.95\n" + + " },\n" + + " { \"category\": \"fiction\",\n" + + " \"author\": \"Evelyn Waugh\",\n" + + " \"title\": \"Sword of Honour\",\n" + + " \"price\": 12.99\n" + + " },\n" + + " { \"category\": \"fiction\",\n" + + " \"author\": \"Herman Melville\",\n" + + " \"title\": \"Moby Dick\",\n" + + " \"isbn\": \"0-553-21311-3\",\n" + + " \"price\": 8.99\n" + + " },\n" + + " { \"category\": \"fiction\",\n" + + " \"author\": \"J. R. R. Tolkien\",\n" + + " \"title\": \"The Lord of the Rings\",\n" + + " \"isbn\": \"0-395-19395-8\",\n" + + " \"price\": 22.99\n" + + " }\n" + + " ],\n" + + " \"bicycle\": {\n" + + " \"color\": \"red\",\n" + + " \"price\": 19.95\n" + + " }\n" + + " }\n" + + "}"; + + @Test + public void read_document_from_root() throws Exception { + + + JsonPath path = JsonPath.compile("$.store"); + + List list = path.read(DOCUMENT); + + System.out.println(list.toString()); + + } + + @Test + public void read_store_book_1() throws Exception { + + + JsonPath path = JsonPath.compile("$.store.book[1]"); + + List list = path.read(DOCUMENT); + + System.out.println(list.toString()); + + } + + @Test + public void read_store_book_wildcard() throws Exception { + JsonPath path = JsonPath.compile("$.store.book[*]"); + + List list = path.read(DOCUMENT); + + System.out.println(list.toString()); + } + + @Test + public void read_store_book_author() throws Exception { + assertThat(JsonPath.read(DOCUMENT, "$.store.book[*].author"), hasItems("Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien")); + } + + + @Test + public void all_authors() throws Exception { + assertThat(JsonPath.read(DOCUMENT, "$..author"), hasItems("Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien")); + } + + + @Test + public void all_store_properties() throws Exception { + List itemsInStore = JsonPath.read(DOCUMENT, "$.store.*"); + + assertEquals(JsonPath.readOne(itemsInStore, "$.[0].[0].author"), "Nigel Rees"); + assertEquals(JsonPath.readOne(itemsInStore, "$.[0][0].author"), "Nigel Rees"); + } + + @Test + public void all_prices_in_store() throws Exception { + + assertThat(JsonPath.read(DOCUMENT, "$.store..price"), hasItems(8.95D, 12.99D, 8.99D, 19.95D)); + + } + + @Test + public void access_array_by_index_from_tail() throws Exception { + + assertThat(JsonPath.readOne(DOCUMENT, "$..book[(@.length-1)].author"), equalTo("J. R. R. Tolkien")); + assertThat(JsonPath.readOne(DOCUMENT, "$..book[-1:].author"), equalTo("J. R. R. Tolkien")); + } + + @Test + public void read_store_book_index_0_and_1() throws Exception { + + assertThat(JsonPath.read(DOCUMENT, "$.store.book[0,1].author"), hasItems("Nigel Rees", "Evelyn Waugh")); + assertTrue(JsonPath.read(DOCUMENT, "$.store.book[0,1].author").size() == 2); + } + + @Test + public void read_store_book_pull_first_2() throws Exception { + + assertThat(JsonPath.read(DOCUMENT, "$.store.book[:2].author"), hasItems("Nigel Rees", "Evelyn Waugh")); + assertTrue(JsonPath.read(DOCUMENT, "$.store.book[:2].author").size() == 2); + } + + @Test + public void read_store_book_filter_by_isbn() throws Exception { + + assertThat(JsonPath.read(DOCUMENT, "$.store.book[?(@.isbn)].isbn"), hasItems("0-553-21311-3", "0-395-19395-8")); + assertTrue(JsonPath.read(DOCUMENT, "$.store.book[?(@.isbn)].isbn").size() == 2); + } + + @Test + public void all_members_of_all_documents() throws Exception { + + List all = JsonPath.read(DOCUMENT, "$..*"); + + System.out.println(StringUtils.join(all, "\n")); + System.out.println(all.toString()); + + } +} diff --git a/json-assert/src/test/java/com/jayway/jsonpath/SplitPathFragmentsTest.java b/json-assert/src/test/java/com/jayway/jsonpath/SplitPathFragmentsTest.java new file mode 100644 index 00000000..88804d7c --- /dev/null +++ b/json-assert/src/test/java/com/jayway/jsonpath/SplitPathFragmentsTest.java @@ -0,0 +1,68 @@ +package com.jayway.jsonpath; + +import org.apache.commons.lang.StringUtils; +import org.junit.Test; + +import static org.hamcrest.Matchers.hasItemInArray; +import static org.hamcrest.Matchers.hasItems; +import static org.junit.Assert.assertThat; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/2/11 + * Time: 1:22 PM + */ +public class SplitPathFragmentsTest { + + /* + 1. "$..book[-1:].foo.bar" + 2. "$.store.book[*].author" + 3. "$..author" + 4. "$.store.*" + 5. "$.store..price" + 6. "$..book[(@.length-1)]" + 7. "$..book[-1:] + 8. "$..book[0,1]" + 9. "$..book[:2]" + 10. "$..book[?(@.isbn)]" + 11. "$..book[?(@.price<10)]" + 12. "$..*" + */ + + + @Test + public void fragments_are_split_correctly() throws Exception { + + assertThat(PathUtil.splitPath("$..book[-1:].foo.bar"), hasItems("$", "..", "[-1:]", "foo", "bar")); + + assertThat(PathUtil.splitPath("$.store.book[*].author"), hasItems("$", "store", "book", "[*]", "author")); + + assertThat(PathUtil.splitPath("$..author"), hasItems("$", "..", "author")); + + assertThat(PathUtil.splitPath("$.store.*"), hasItems("$", "store", "*")); + + assertThat(PathUtil.splitPath("$.store..price"), hasItems("$", "store", "..", "price")); + + assertThat(PathUtil.splitPath("$..book[(@.length-1)]"), hasItems("$", "..", "book", "[(@.length-1)]")); + + assertThat(PathUtil.splitPath("$..book[-1:]"), hasItems("$", "..", "book", "[-1:]")); + + assertThat(PathUtil.splitPath("$..book[0,1]"), hasItems("$", "..", "book", "[0,1]")); + + assertThat(PathUtil.splitPath("$..book[:2]"), hasItems("$", "..", "book", "[:2]")); + + assertThat(PathUtil.splitPath("$..book[?(@.isbn)]"), hasItems("$", "..", "book", "[?(@.isbn)]")); + + assertThat(PathUtil.splitPath("$..book[?(@.price<10)]"), hasItems("$", "..", "book", "[?(@.price<10)]")); + + assertThat(PathUtil.splitPath("$..*"), hasItems("$", "..", "*")); + + assertThat(PathUtil.splitPath("$.[0][1].author"), hasItems("$", "[0]", "[1]", "author")); + + assertThat(PathUtil.splitPath("$.[0].[1].author"), hasItems("$", "[0]", "[1]", "author")); + } + + + +}