org.nlab.json.stream.jsonpath.evaluation.EvaluatePath Maven / Gradle / Ivy
package org.nlab.json.stream.jsonpath.evaluation;
import java.util.function.Consumer;
import org.nlab.json.stream.context.StreamContext;
import org.nlab.json.stream.jsonpath.path.PathArrayNode;
import org.nlab.json.stream.jsonpath.path.PathCurrentNode;
import org.nlab.json.stream.jsonpath.path.PathDescendantNode;
import org.nlab.json.stream.jsonpath.path.PathNode;
import org.nlab.json.stream.jsonpath.path.PathObjectNode;
import org.nlab.json.stream.jsonpath.path.PathRootNode;
import org.nlab.json.stream.context.token.ArrayToken;
import org.nlab.json.stream.context.token.ObjectToken;
import org.nlab.json.stream.context.token.Token;
import org.nlab.json.stream.context.token.RootToken;
/**
* Created by nlabrot on 19/04/16.
*/
public class EvaluatePath {
private Consumer callback;
public EvaluatePath(Consumer callback) {
this.callback = callback;
}
public void evaluateNext(StreamContext context, int index, PathNode node) {
if (node == null || index >= context.getElements().size()) {
return;
}
Token parserToken = context.getElements().get(index);
if (parserToken instanceof RootToken) {
if (node instanceof PathRootNode) {
evaluateNext(context, index + 1, node.getChild());
} else if (node instanceof PathCurrentNode) {
evaluatePathCurrent(context, index, node);
}
} else if (parserToken instanceof ArrayToken && node instanceof PathArrayNode) {
evaluateArray(context, index, (PathArrayNode) node);
} else if (parserToken instanceof ObjectToken && node instanceof PathObjectNode) {
evaluateObject(context, index, (PathObjectNode) node);
} else if (node instanceof PathDescendantNode){
evaluatePathCurrent(context, index, node);
}
}
public void evaluatePathCurrent(StreamContext context, int index, PathNode node) {
for (int i = index; i <= context.getElements().size(); i++) {
evaluateNext(context, i, node.getChild());
}
}
public void evaluateArray(StreamContext context, int index, PathArrayNode pathArrayNode) {
ArrayToken arrayToken = (ArrayToken) context.getElements().get(index);
if (pathArrayNode.getIndex().matchIndex(arrayToken.getIndex())) {
// match if next node is leaf and next node is an array or an object uninitialized or a literal and there is no next path node
if (index + 2 == context.getElements().size()
&& (context.getElements().get(index + 1).isPreInit() || context.getElements().get(index + 1).isLiteral())
&& pathArrayNode.getChild() == null) {
callback.accept(context);
return;
} else {
evaluateNext(context, index + 1, pathArrayNode.getChild());
}
}
}
private void evaluateObject(StreamContext context, int index, PathObjectNode pathObjectNode) {
ObjectToken objectToken = (ObjectToken) context.getElements().get(index);
if (objectToken.isKeyInit() && objectToken.getKey().equals(pathObjectNode.getName())) {
// match if both node and path reached last and node does not yet has it's value parsed
// match if both node and path reached last and node has it's value parsed but not initialized in case of object or array
/* if (index + 1 >= context.getElements().size() && !objectToken.isValueInit() && pathObjectNode.getChild() == null) {
callback.accept(context);
} else {
evaluateNext(context, index + 1, pathObjectNode.getChild());
}*/
// match if path reached last and node is prior last and node has it's value parsed but not initialized in case of object or array
if (pathObjectNode.getChild() == null){
if (index + 2 == context.getElements().size()) {
Token nextToken = context.getElements().get(index + 1);
if (nextToken instanceof ObjectToken && nextToken.isPreInit()){
callback.accept(context);
}
if (nextToken instanceof ArrayToken && ((ArrayToken) nextToken).isPreInit()){
callback.accept(context);
}
if (nextToken.isLiteral()){
callback.accept(context);
}
}
}else{
evaluateNext(context, index + 1, pathObjectNode.getChild());
}
/*
if (index + 1 >= context.getElements().size() && pathObjectNode.getChild() == null) {
if (objectToken instanceof ObjectToken !objectToken.isValueInit())
callback.accept(context);
} else {
evaluateNext(context, index + 1, pathObjectNode.getChild());
}*/
}
}
public Consumer getCallback() {
return callback;
}
public void setCallback(Consumer callback) {
this.callback = callback;
}
}