Browse Source

caret 추가

pull/621/head
KimSeokWon 5 years ago
parent
commit
92187b13c8
  1. 90
      json-path/src/main/java/com/jayway/jsonpath/internal/path/CaretPathToken.java
  2. 19
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java
  3. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PathTokenFactory.java
  4. 1
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PropertyPathToken.java
  5. 12
      json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java
  6. 10
      json-path/src/main/java/com/jayway/jsonpath/internal/path/ScanPathToken.java
  7. 44
      json-path/src/test/java/com/jayway/jsonpath/CaretTest.java
  8. 3796
      json-path/src/test/resources/issue_caret.json

90
json-path/src/main/java/com/jayway/jsonpath/internal/path/CaretPathToken.java

@ -0,0 +1,90 @@
package com.jayway.jsonpath.internal.path;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.internal.Utils;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
public class CaretPathToken extends PathToken {
public final static char SINGLE_QUOTE = '\'';
public final static char CARET = '^';
@Override
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if ( isRoot() ) return;
String evalPath = Utils.concat(currentPath, getPathFragment());
Object p = getParentModel(currentPath, model, ctx);
if ( p == null ) return;
PathRef pathRef = ctx.forUpdate() ? parent : PathRef.NO_OP;
if ( isLeaf() ) {
ctx.addResult(evalPath, pathRef, p);
} else {
next().evaluate(evalPath, pathRef, p, ctx);
}
}
private Object getParentModel(final String path, final Object model, final EvaluationContextImpl ctx) {
Object root = ctx.rootDocument();
List list = tokenizePath(path);
list = list.subList(0, list.size() - getParentDepth(path));
Object p = root;
Object last = null;
for ( Object o : list ) {
last = p;
p = searchObject(o, p, ctx);
}
return p;
}
private int getParentDepth(final String path) {
int i = 0;
while ( true ) {
if ( path.charAt(path.length() - 1 - i) == CARET ) {
i++;
} else {
break;
}
}
return i;
}
private Object searchObject(Object key, Object o, final EvaluationContextImpl ctx) {
if ( key instanceof String ) {
return ctx.jsonProvider().getMapValue(o, (String)key);
} else if ( key instanceof Integer ) {
return ctx.jsonProvider().getArrayIndex(o, (Integer)key);
}
return null;
}
private List<Object> tokenizePath(final String path) {
StringTokenizer st = new StringTokenizer(path, "$[]^");
List obj = new ArrayList();
while ( st.hasMoreTokens() ) {
String token = st.nextToken().trim();
if ( token.indexOf(SINGLE_QUOTE) == 0 ) {
obj.add(token.substring(1, token.length() - 1));
} else {
try {
obj.add(Integer.parseInt(token));
} catch ( NumberFormatException ex) {
;
}
}
}
return obj;
}
@Override
public boolean isTokenDefinite() {
return false;
}
@Override
protected String getPathFragment() {
return "^";
}
}

19
json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java

@ -31,6 +31,7 @@ public class PathCompiler {
private static final char WILDCARD = '*'; private static final char WILDCARD = '*';
private static final char PERIOD = '.'; private static final char PERIOD = '.';
private static final char CARET = '^';
private static final char SPACE = ' '; private static final char SPACE = ' ';
private static final char TAB = '\t'; private static final char TAB = '\t';
private static final char CR = '\r'; private static final char CR = '\r';
@ -147,12 +148,28 @@ public class PathCompiler {
case WILDCARD: case WILDCARD:
return readWildCardToken(appender) || return readWildCardToken(appender) ||
fail("Could not parse token starting at position " + path.position()); fail("Could not parse token starting at position " + path.position());
case CARET:
return readCaretToken(appender) ||
fail("Could not parse token starting at position " + path.position());
default: default:
return readPropertyOrFunctionToken(appender) || return readPropertyOrFunctionToken(appender) ||
fail("Could not parse token starting at position " + path.position()); fail("Could not parse token starting at position " + path.position());
} }
} }
//
// ^
//
private boolean readCaretToken(PathTokenAppender appender) {
if (false == path.currentCharIs(CARET)) {
return false;
}
path.incrementPosition(1);
appender.appendPathToken(PathTokenFactory.createCaretPathToken());
return path.currentIsTail() || readNextToken(appender);
}
// //
// . and .. // . and ..
// //
@ -175,7 +192,7 @@ public class PathCompiler {
// fooBar or fooBar() // fooBar or fooBar()
// //
private boolean readPropertyOrFunctionToken(PathTokenAppender appender) { private boolean readPropertyOrFunctionToken(PathTokenAppender appender) {
if (path.currentCharIs(OPEN_SQUARE_BRACKET) || path.currentCharIs(WILDCARD) || path.currentCharIs(PERIOD) || path.currentCharIs(SPACE)) { if (path.currentCharIs(OPEN_SQUARE_BRACKET) || path.currentCharIs(WILDCARD) || path.currentCharIs(PERIOD) || path.currentCharIs(CARET) || path.currentCharIs(SPACE)) {
return false; return false;
} }
int startPosition = path.position(); int startPosition = path.position();

4
json-path/src/main/java/com/jayway/jsonpath/internal/path/PathTokenFactory.java

@ -49,4 +49,8 @@ public class PathTokenFactory {
public static PathToken createFunctionPathToken(String function, List<Parameter> parameters) { public static PathToken createFunctionPathToken(String function, List<Parameter> parameters) {
return new FunctionPathToken(function, parameters); return new FunctionPathToken(function, parameters);
} }
public static PathToken createCaretPathToken() {
return new CaretPathToken();
}
} }

1
json-path/src/main/java/com/jayway/jsonpath/internal/path/PropertyPathToken.java

@ -36,6 +36,7 @@ class PropertyPathToken extends PathToken {
if (properties.isEmpty()) { if (properties.isEmpty()) {
throw new InvalidPathException("Empty properties"); throw new InvalidPathException("Empty properties");
} }
setDepth(depth + 1);
this.properties = properties; this.properties = properties;
this.stringDelimiter = Character.toString(stringDelimiter); this.stringDelimiter = Character.toString(stringDelimiter);
} }

12
json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java

@ -15,6 +15,8 @@
package com.jayway.jsonpath.internal.path; package com.jayway.jsonpath.internal.path;
import com.jayway.jsonpath.internal.PathRef; import com.jayway.jsonpath.internal.PathRef;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* *
@ -25,6 +27,7 @@ public class RootPathToken extends PathToken {
private int tokenCount; private int tokenCount;
private final String rootToken; private final String rootToken;
private static final Logger logger = LoggerFactory.getLogger(RootPathToken.class);
RootPathToken(char rootToken) { RootPathToken(char rootToken) {
this.rootToken = Character.toString(rootToken); this.rootToken = Character.toString(rootToken);
@ -47,6 +50,9 @@ public class RootPathToken extends PathToken {
return new PathTokenAppender(){ return new PathTokenAppender(){
@Override @Override
public PathTokenAppender appendPathToken(PathToken next) { public PathTokenAppender appendPathToken(PathToken next) {
if ( logger.isDebugEnabled() ) {
logger.debug("append: " + next);
}
append(next); append(next);
return this; return this;
} }
@ -56,9 +62,15 @@ public class RootPathToken extends PathToken {
@Override @Override
public void evaluate(String currentPath, PathRef pathRef, Object model, EvaluationContextImpl ctx) { public void evaluate(String currentPath, PathRef pathRef, Object model, EvaluationContextImpl ctx) {
if (isLeaf()) { if (isLeaf()) {
if ( logger.isDebugEnabled() ) {
logger.debug("next(): " + next());
}
PathRef op = ctx.forUpdate() ? pathRef : PathRef.NO_OP; PathRef op = ctx.forUpdate() ? pathRef : PathRef.NO_OP;
ctx.addResult(rootToken, op, model); ctx.addResult(rootToken, op, model);
} else { } else {
if ( logger.isDebugEnabled() ) {
logger.debug("next(): " + next());
}
next().evaluate(rootToken, pathRef, model, ctx); next().evaluate(rootToken, pathRef, model, ctx);
} }
} }

10
json-path/src/main/java/com/jayway/jsonpath/internal/path/ScanPathToken.java

@ -95,6 +95,8 @@ public class ScanPathToken extends PathToken {
return new WildcardPathTokenPredicate(); return new WildcardPathTokenPredicate();
} else if (target instanceof PredicatePathToken) { } else if (target instanceof PredicatePathToken) {
return new FilterPathTokenPredicate(target, ctx); return new FilterPathTokenPredicate(target, ctx);
} else if ( target instanceof CaretPathToken ) {
return new CaretPathTokenPredicate();
} else { } else {
return FALSE_PREDICATE; return FALSE_PREDICATE;
} }
@ -146,6 +148,14 @@ public class ScanPathToken extends PathToken {
} }
} }
private static final class CaretPathTokenPredicate implements Predicate {
@Override
public boolean matches(Object model) {
return true;
}
}
private static final class ArrayPathTokenPredicate implements Predicate { private static final class ArrayPathTokenPredicate implements Predicate {
private final EvaluationContextImpl ctx; private final EvaluationContextImpl ctx;

44
json-path/src/test/java/com/jayway/jsonpath/CaretTest.java

@ -0,0 +1,44 @@
package com.jayway.jsonpath;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static com.jayway.jsonpath.JsonPath.parse;
import static com.jayway.jsonpath.JsonPath.read;
import static java.util.Collections.emptyMap;
import static org.assertj.core.api.Assertions.assertThat;
public class CaretTest extends BaseTest {
private static final Map<String, Object> EMPTY_MAP = emptyMap();
@Test
public void get_parent_node() {
try(InputStream is = this.getClass().getResourceAsStream("/issue_caret.json")) {
Object result = read(is, "$..ExtendedResult[?(@.:Type =='ER' && @.:Code == 'FX')].Extension[?(@.:Code == 'PENALTY' && @.:Value)]^^^^^^[':SortOrder']");
System.out.println(result.toString());
} catch ( IOException ioex) {
ioex.printStackTrace();
}
}
// Helper converter implementation for test cases.
private class ToStringMapFunction implements MapFunction {
@Override
public Object map(Object currentValue, Configuration configuration) {
return currentValue.toString()+"converted";
}
}
}

3796
json-path/src/test/resources/issue_caret.json

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save