Browse Source

fixed array slizing.

pull/29/head
Kalle Stenflo 11 years ago
parent
commit
c9f4cd5a3d
  1. 50
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayIndexFilter.java
  2. 92
      json-path/src/test/java/com/jayway/jsonpath/ArraySlicingTest.java
  3. 6
      json-path/src/test/java/com/jayway/jsonpath/ComplianceTest.java
  4. 2
      json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java

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

@ -14,6 +14,7 @@
*/ */
package com.jayway.jsonpath.internal.filter; package com.jayway.jsonpath.internal.filter;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.spi.JsonProvider; import com.jayway.jsonpath.spi.JsonProvider;
import java.util.List; import java.util.List;
@ -27,32 +28,37 @@ public class ArrayIndexFilter extends PathTokenFilter {
private static final Pattern SINGLE_ARRAY_INDEX_PATTERN = Pattern.compile("\\[\\d+\\]"); private static final Pattern SINGLE_ARRAY_INDEX_PATTERN = Pattern.compile("\\[\\d+\\]");
private static final Pattern COMMA = Pattern.compile(","); private static final Pattern COMMA = Pattern.compile(",");
private static final Pattern SPACE = Pattern.compile(" "); private static final Pattern SPACE = Pattern.compile(" ");
private static final String OPERATOR = ":";
private final String trimmedCondition; private final String trimmedCondition;
private boolean usesLenght;
public ArrayIndexFilter(String condition) { public ArrayIndexFilter(String condition) {
super(condition); super(condition);
// remove '[' and ']'
String trimmedCondition = trim(condition, 1, 1); String trimmedCondition = trim(condition, 1, 1);
if(trimmedCondition.contains("@.length")){ this.usesLenght = trimmedCondition.contains("@.length");
// resolve '@.length'
if(usesLenght){
trimmedCondition = trim(trimmedCondition, 1, 1); trimmedCondition = trim(trimmedCondition, 1, 1);
trimmedCondition = trimmedCondition.replace("@.length", ""); trimmedCondition = trimmedCondition.replace("@.length", "");
trimmedCondition = trimmedCondition + ":"; trimmedCondition = trimmedCondition + OPERATOR;
} }
this.trimmedCondition = trimmedCondition; this.trimmedCondition = trimmedCondition;
} }
@Override @Override
public Object filter(Object obj,JsonProvider jsonProvider) { public Object filter(Object obj,JsonProvider jsonProvider) {
List<Object> src = jsonProvider.toList(obj); List<Object> src = jsonProvider.toList(obj);
List<Object> result = jsonProvider.createList(); List<Object> result = jsonProvider.createList();
if (trimmedCondition.contains(OPERATOR)) {
if (trimmedCondition.startsWith(OPERATOR)) {
if (trimmedCondition.startsWith(":")) {
String trimmedCondition = trim(this.trimmedCondition, 1, 0); String trimmedCondition = trim(this.trimmedCondition, 1, 0);
int get = Integer.parseInt(trimmedCondition); int get = Integer.parseInt(trimmedCondition);
for (int i = 0; i < get; i++) { for (int i = 0; i < get; i++) {
@ -60,11 +66,35 @@ public class ArrayIndexFilter extends PathTokenFilter {
} }
return result; return result;
} else if (trimmedCondition.endsWith(":")) { } else if (trimmedCondition.endsWith(OPERATOR)) {
String trimmedCondition = trim(SPACE.matcher(this.trimmedCondition).replaceAll(""), 1, 1); String trimmedCondition = trim(SPACE.matcher(this.trimmedCondition).replaceAll(""), 0, 1);
int get = Integer.parseInt(trimmedCondition); int get = Integer.parseInt(trimmedCondition);
return src.get(src.size() - get); if(get > 0 || usesLenght){
if(get > 0){
get = get * -1;
}
return src.get(src.size() + get);
} else {
int start = src.size() + get;
int stop = src.size();
for (int i = start; i < stop; i ++){
result.add(src.get(i));
}
return result;
}
} else {
String[] indexes = this.trimmedCondition.split(OPERATOR);
int start = Integer.parseInt(indexes[0]);
int stop = Integer.parseInt(indexes[1]);
for (int i = start; i < stop; i ++){
result.add(src.get(i));
}
return result;
}
} else { } else {
String[] indexArr = COMMA.split(trimmedCondition); String[] indexArr = COMMA.split(trimmedCondition);

92
json-path/src/test/java/com/jayway/jsonpath/ArraySlicingTest.java

@ -0,0 +1,92 @@
package com.jayway.jsonpath;
import org.hamcrest.Matchers;
import org.junit.Test;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* User: kalle
* Date: 8/20/13
* Time: 9:22 AM
*
* If you have a list
* nums = [1, 3, 5, 7, 8, 13, 20]
* then it is possible to slice by using a notation similar to element retrieval:
*
* nums[3] #equals 7, no slicing
* nums[:3] #equals [1, 3, 5], from index 0 (inclusive) until index 3 (exclusive)
* nums[1:5] #equals [3, 5, 7, 8]
* nums[-3:] #equals [8, 13, 20]
* nums[3:] #equals [8, 13, 20]
*
* Note that Python allows negative list indices. The index -1 represents the last element, -2 the penultimate element, etc.
* Python also allows a step property by appending an extra colon and a value. For example:
*
* nums[3::] #equals [7, 8, 13, 20], same as nums[3:]
* nums[::3] #equals [1, 7, 20] (starting at index 0 and getting every third element)
* nums[1:5:2] #equals [3, 7] (from index 1 until index 5 and getting every second element)
*
*/
public class ArraySlicingTest {
public static final String JSON_ARRAY = "[1, 3, 5, 7, 8, 13, 20]";
@Test
public void get_by_position(){
int result = JsonPath.read(JSON_ARRAY, "$[3]");
assertEquals(7, result);
}
@Test
public void get_from_index(){
List<Integer> result = JsonPath.read(JSON_ARRAY, "$[:3]");
assertThat(result, Matchers.contains(1,3,5));
}
@Test
public void get_between_index(){
List<Integer> result = JsonPath.read(JSON_ARRAY, "$[1:5]");
assertThat(result, Matchers.contains(3, 5, 7, 8));
}
@Test
public void get_between_index_2(){
List<Integer> result = JsonPath.read(JSON_ARRAY, "$[0:1]");
assertThat(result, Matchers.contains(1));
}
@Test(expected = IndexOutOfBoundsException.class)
public void get_between_index_out_of_bounds(){
List<Integer> result = JsonPath.read(JSON_ARRAY, "$[1:15]");
}
@Test
public void get_from_tail_index(){
List<Integer> result = JsonPath.read(JSON_ARRAY, "$[-3:]");
assertThat(result, Matchers.contains(8, 13, 20));
}
@Test
public void get_from_tail(){
int result = JsonPath.read(JSON_ARRAY, "$[3:]");
assertEquals(8, result);
}
@Test
public void get_from_tail_length(){
int result = JsonPath.read(JSON_ARRAY, "$[(@.length -3)]");
assertEquals(8, result);
}
@Test
public void get_indexes(){
List<Integer> result = JsonPath.read(JSON_ARRAY, "$[0,1,2]");
assertThat(result, Matchers.contains(1,3,5));
}
}

6
json-path/src/test/java/com/jayway/jsonpath/ComplianceTest.java

@ -8,6 +8,7 @@ import java.util.Map;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/** /**
* test defined in http://jsonpath.googlecode.com/svn/trunk/tests/jsonpath-test-js.html * test defined in http://jsonpath.googlecode.com/svn/trunk/tests/jsonpath-test-js.html
@ -44,7 +45,10 @@ public class ComplianceTest {
new Double(3.14), new Double(3.14),
new Boolean(true), new Boolean(true),
(Comparable)null)); (Comparable)null));
assertThat(JsonPath.<Boolean>read(json, "$[-1:]"), is(equalTo(null)));
List<Object> res = JsonPath.read(json, "$[-1:]");
assertTrue(res.get(0) == null);
} }
@Test @Test

2
json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java

@ -190,7 +190,7 @@ public class JsonPathTest {
public void access_array_by_index_from_tail() throws Exception { public void access_array_by_index_from_tail() throws Exception {
assertThat(JsonPath.<String>read(DOCUMENT, "$..book[(@.length-1)].author"), equalTo("J. R. R. Tolkien")); assertThat(JsonPath.<String>read(DOCUMENT, "$..book[(@.length-1)].author"), equalTo("J. R. R. Tolkien"));
assertThat(JsonPath.<String>read(DOCUMENT, "$..book[-1:].author"), equalTo("J. R. R. Tolkien")); assertThat(JsonPath.<String>read(DOCUMENT, "$..book[1:].author"), equalTo("J. R. R. Tolkien"));
} }
@Test @Test

Loading…
Cancel
Save