Commit c352e39c authored by Administrator's avatar Administrator

update

parent 8147e17a
package com.virjar.superappium.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
/**
* some utils migrated from guava
*/
public class Lists {
public static <E> ArrayList<E> newArrayList(E... elements) {
// Avoid integer overflow when a large array is passed in
int capacity = computeArrayListCapacity(elements.length);
ArrayList<E> list = new ArrayList<E>(capacity);
Collections.addAll(list, elements);
return list;
}
static int computeArrayListCapacity(int arraySize) {
return saturatedCast(5L + arraySize + (arraySize / 10));
}
/**
* Returns the {@code int} nearest in value to {@code value}.
*
* @param value any {@code long} value
* @return the same value cast to {@code int} if it is in the range of the
* {@code int} type, {@link Integer#MAX_VALUE} if it is too large,
* or {@link Integer#MIN_VALUE} if it is too small
*/
public static int saturatedCast(long value) {
if (value > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
if (value < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
return (int) value;
}
public static <E> LinkedList<E> newLinkedList() {
return new LinkedList<E>();
}
}
package com.virjar.superappium.xpath;
import com.virjar.superappium.xpath.exception.XpathSyntaxErrorException;
import com.virjar.superappium.xpath.model.XpathEvaluator;
public class XpathParser {
public XpathParser(String subXpath) {
}
public static void compile(String s) throws XpathSyntaxErrorException {
}
public XpathEvaluator parse() {
return null;
}
}
package com.virjar.superappium.xpath.exception;
public class EvaluateException extends RuntimeException {
public EvaluateException() {
}
public EvaluateException(Throwable cause) {
super(cause);
}
public EvaluateException(String message) {
super(message);
}
public EvaluateException(String message, Throwable cause) {
super(message, cause);
}
public EvaluateException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.virjar.superappium.xpath.exception;
public class NoSuchAxisException extends XpathSyntaxErrorException {
public NoSuchAxisException(int errorPos, String msg) {
super(errorPos, msg);
}
}
\ No newline at end of file
package com.virjar.superappium.xpath.function;
import android.util.Log;
import com.virjar.superappium.util.Constants;
import com.virjar.superappium.xpath.function.axis.AxisFunction;
import com.virjar.superappium.xpath.function.filter.FilterFunction;
import com.virjar.superappium.xpath.function.select.SelectFunction;
import java.util.HashMap;
import java.util.Map;
public class FunctionEnv {
private static Map<String, SelectFunction> selectFunctions = new HashMap<>();
private static Map<String, FilterFunction> filterFunctions = new HashMap<>();
private static Map<String, AxisFunction> axisFunctions = new HashMap<>();
static {
registerAllSelectFunctions();
registerAllFilterFunctions();
registerAllAxisFunctions();
}
public static SelectFunction getSelectFunction(String functionName) {
return selectFunctions.get(functionName);
}
public static FilterFunction getFilterFunction(String functionName) {
return filterFunctions.get(functionName);
}
public static AxisFunction getAxisFunction(String functionName) {
return axisFunctions.get(functionName);
}
public synchronized static void registerSelectFunction(SelectFunction selectFunction) {
if (selectFunctions.containsKey(selectFunction.getName())) {
Log.w(Constants.TAG, "register a duplicate select function " + selectFunction.getName());
}
selectFunctions.put(selectFunction.getName(), selectFunction);
}
public synchronized static void registerFilterFunction(FilterFunction filterFunction) {
if (filterFunctions.containsKey(filterFunction.getName())) {
Log.w(Constants.TAG, "register a duplicate filter function " + filterFunction.getName());
}
filterFunctions.put(filterFunction.getName(), filterFunction);
}
public synchronized static void registerAxisFunciton(AxisFunction axisFunction) {
if (axisFunctions.containsKey(axisFunction.getName())) {
Log.w(Constants.TAG, "register a duplicate axis function " + axisFunction.getName());
}
axisFunctions.put(axisFunction.getName(), axisFunction);
}
private static void registerAllSelectFunctions() {
}
private static void registerAllFilterFunctions() {
}
private static void registerAllAxisFunctions() {
}
}
package com.virjar.superappium.xpath.function;
public interface NameAware {
String getName();
}
package com.virjar.superappium.xpath.function.axis;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.function.NameAware;
import java.util.List;
public interface AxisFunction extends NameAware {
//TODO 是否允许轴函数存在参数
List<ViewImage> call(ViewImage viewImage, List<String> args);
}
package com.virjar.superappium.xpath.function.filter;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.function.NameAware;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import java.util.List;
public interface FilterFunction extends NameAware {
Object call(ViewImage viewImage, List<SyntaxNode> params);
}
package com.virjar.superappium.xpath.function.select;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.function.NameAware;
import com.virjar.superappium.xpath.model.XNode;
import com.virjar.superappium.xpath.model.XpathNode;
import java.util.List;
public interface SelectFunction extends NameAware {
List<XNode> call(XpathNode.ScopeEm scopeEm, List<ViewImage> elements, List<String> args);
}
package com.virjar.superappium.xpath.model;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.util.Lists;
import com.virjar.superappium.xpath.function.FunctionEnv;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import lombok.Getter;
public class Predicate {
private SyntaxNode syntaxNode;
@Getter
private String predicateStr;
public Predicate(String predicateStr, SyntaxNode syntaxNode) {
this.predicateStr = predicateStr;
this.syntaxNode = syntaxNode;
}
boolean isValid(ViewImage element) {
return (Boolean) FunctionEnv.getFilterFunction("sipSoupPredictJudge").call(element,
Lists.newArrayList(syntaxNode));
}
}
......@@ -8,4 +8,8 @@ public class XNodes extends LinkedList<XNode> {
public XNodes(List<XNode> handleNode) {
super(handleNode);
}
public XNodes(XNode e) {
add(e);
}
}
package com.virjar.superappium.xpath.model;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.util.Lists;
import com.virjar.superappium.xpath.function.axis.AxisFunction;
import com.virjar.superappium.xpath.util.XpathUtil;
import java.util.Iterator;
import java.util.LinkedList;
......@@ -47,7 +50,7 @@ public abstract class XpathEvaluator {
if (axis != null) {
contextElements = Lists.newLinkedList();
for (ViewImage element : elements) {
ViewImage call = axis.call(element, xpathNode.getAxisParams());
List<ViewImage> call = axis.call(element, xpathNode.getAxisParams());
if (call != null) {
contextElements.addAll(call);
}
......@@ -57,21 +60,32 @@ public abstract class XpathEvaluator {
}
// 调用抽取函数
List<XNode> SIPNodes = xpathNode.getSelectFunction().call(xpathNode.getScopeEm(),
new Elements(contextElements), xpathNode.getSelectParams());
List<XNode> xNodesList = xpathNode.getSelectFunction().call(xpathNode.getScopeEm(),
contextElements, xpathNode.getSelectParams());
// 谓语过滤
if (xpathNode.getPredicate() == null) {
return SIPNodes;
if (xpathNode.getPredicates() == null) {
return xNodesList;
}
// 谓语只支持对元素过滤,非元素节点直接被过滤
return Lists.newLinkedList(Iterables.filter(SIPNodes, new Predicate<XNode>() {
@Override
public boolean apply(XNode input) {
return xpathNode.getPredicate().isValid(input.getElement());
List<XNode> finalResult = Lists.newLinkedList();
//两层循环
for (XNode xNode : xNodesList) {
if (xNode.isText()) {
continue;
}
}));
boolean valid = true;
for (Predicate predicate : xpathNode.getPredicates()) {
if (!predicate.isValid(xNode.getElement())) {
valid = false;
break;
}
}
if (valid) {
finalResult.add(xNode);
}
}
return finalResult;
}
@Override
......
package com.virjar.superappium.xpath.model;
import com.virjar.superappium.xpath.function.axis.AxisFunction;
import com.virjar.superappium.xpath.function.select.SelectFunction;
import java.util.LinkedList;
import java.util.List;
import lombok.Getter;
......@@ -44,7 +48,7 @@ public class XpathNode {
*/
@Getter
@Setter
private Predicate predicate;
private LinkedList<Predicate> predicates = new LinkedList<>();
@Setter
@Getter
......
......@@ -2,7 +2,10 @@ package com.virjar.superappium.xpath.parser;
import com.virjar.superappium.util.StringUtils;
import lombok.Getter;
public class TokenQueue {
@Getter
protected String queue;
protected int pos = 0;
......
package com.virjar.superappium.xpath.parser;
import com.virjar.superappium.util.Lists;
import com.virjar.superappium.util.StringUtils;
import com.virjar.superappium.xpath.XpathParser;
import com.virjar.superappium.xpath.exception.NoSuchAxisException;
import com.virjar.superappium.xpath.exception.XpathSyntaxErrorException;
import com.virjar.superappium.xpath.function.FunctionEnv;
import com.virjar.superappium.xpath.function.axis.AxisFunction;
import com.virjar.superappium.xpath.model.Predicate;
import com.virjar.superappium.xpath.model.XpathEvaluator;
import com.virjar.superappium.xpath.model.XpathNode;
import com.virjar.superappium.xpath.parser.expression.ExpressionParser;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import java.util.ArrayList;
import java.util.HashMap;
......@@ -294,7 +301,7 @@ public class XpathStateMachine {
String predicate = stateMachine.tokenQueue.chompBalanced('[', ']');
SyntaxNode predicateTree = new ExpressionParser(new TokenQueue(predicate)).parse();
stateMachine.xpathChain.getLast()
.setPredicate(new Predicate(StringUtils.trimToEmpty(predicate), predicateTree));
.getPredicates().add(new Predicate(StringUtils.trimToEmpty(predicate), predicateTree));
}
// check
stateMachine.tokenQueue.consumeWhitespace();
......
package com.virjar.superappium.xpath.parser.expression;
import com.virjar.superappium.util.Lists;
import com.virjar.superappium.xpath.exception.XpathSyntaxErrorException;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenAnalysisRegistry;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
import java.util.EmptyStackException;
import java.util.List;
import java.util.Stack;
import lombok.Getter;
public class ExpressionParser {
private TokenQueue expressionTokenQueue;
public ExpressionParser(TokenQueue expressionTokenQueue) {
this.expressionTokenQueue = expressionTokenQueue;
}
private SyntaxNode innerParse() throws XpathSyntaxErrorException {
// 表达式拆分成token流
List<TokenHolder> tokenStream = tokenStream();
// 构建逆波兰式
Stack<TokenHolder> stack = new Stack<>();
// RPN就是逆波兰式的含义
List<TokenHolder> RPN = Lists.newLinkedList();
TokenHolder bottom = new TokenHolder("#", null);
stack.push(bottom);
for (TokenHolder tokenHolder : tokenStream) {
if (tokenHolder.type.equals(Token.OPERATOR)) {
TokenHolder preSymbol = stack.peek();
while (compareSymbolPripority(tokenHolder, preSymbol) <= 0) {
RPN.add(preSymbol);
stack.pop();
preSymbol = stack.peek();
}
stack.push(tokenHolder);
} else {
RPN.add(tokenHolder);
}
}
while (!stack.peek().expression.equals("#")) {
RPN.add(stack.pop());
}
// 构建计算树
Stack<SyntaxNode> computeStack = new Stack<>();
for (TokenHolder tokenHolder : RPN) {
if (tokenHolder.type.equals(Token.OPERATOR)) {
SyntaxNode right = computeStack.pop();
SyntaxNode left = computeStack.pop();
computeStack.push(buildAlgorithmUnit(tokenHolder, left, right));
} else {
computeStack.push(buildByTokenHolder(tokenHolder));
}
}
return computeStack.pop();
}
public SyntaxNode parse() throws XpathSyntaxErrorException {
try {
return innerParse();
} catch (EmptyStackException e) {
throw new XpathSyntaxErrorException(0, "不能识别表达式:" + expressionTokenQueue.getQueue(), e);
}
}
private SyntaxNode buildAlgorithmUnit(TokenHolder tokenHolder, SyntaxNode left, SyntaxNode right) {
// 对于计算树,属于内部节点,需要附加左右操作树,不能单纯根据token信息产生节点
// Preconditions.checkArgument(tokenHolder.type.equals(Token.OPERATOR));
AlgorithmUnit algorithmUnit = OperatorEnv.createByName(tokenHolder.expression);
algorithmUnit.setLeft(left);
algorithmUnit.setRight(right);
return algorithmUnit;
}
/**
* 非操作符的节点构建,如函数,xpath表达式,常量,数字等,他们的构造方法和计算树无关,是表达式里面最原始的计算叶节点
*
* @param tokenHolder token数据
* @return 用来挂在计算树上面的叶节点
*/
private SyntaxNode buildByTokenHolder(TokenHolder tokenHolder) throws XpathSyntaxErrorException {
//Preconditions.checkArgument(!tokenHolder.type.equals(Token.OPERATOR));
// return TokenNodeFactory.hintAndGen(tokenHolder);
return TokenAnalysisRegistry.findHandler(tokenHolder.getType()).parseToken(tokenHolder.expression);
}
private int compareSymbolPripority(TokenHolder first, TokenHolder second) {
// 不能直接减,否则可能溢出
return Integer.valueOf(OperatorEnv.judgePriority(first.expression))
.compareTo(OperatorEnv.judgePriority(second.expression));
}
private List<TokenHolder> tokenStream() throws XpathSyntaxErrorException {
List<TokenHolder> tokenStream = Lists.newLinkedList();
// java不支持逗号表达式,这么做达到了逗号表达式的效果
while ((expressionTokenQueue.consumeWhitespace() || !expressionTokenQueue.consumeWhitespace())
&& !expressionTokenQueue.isEmpty()) {
boolean hint = false;
for (TokenConsumer tokenConsumer : TokenAnalysisRegistry.consumerIterable()) {
String consume = tokenConsumer.consume(expressionTokenQueue);
if (consume == null) {
continue;
}
hint = true;
tokenStream.add(new TokenHolder(consume, tokenConsumer.tokenType()));
break;
}
if (!hint) {
// 不成功,报错
throw new XpathSyntaxErrorException(expressionTokenQueue.nowPosition(), "can not parse predicate"
+ expressionTokenQueue.getQueue() + " for token " + expressionTokenQueue.remainder());
}
}
return tokenStream;
}
public static class TokenHolder {
public TokenHolder(String expression, String type) {
this.expression = expression;
this.type = type;
}
@Getter
private String type;
@Getter
private String expression;
@Override
public String toString() {
return expression;
}
}
}
package com.virjar.superappium.xpath.parser.expression;
import com.virjar.superappium.util.Lists;
import com.virjar.superappium.util.StringUtils;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.parser.expression.operator.OpKey;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import lombok.Getter;
public class OperatorEnv {
private static TreeSet<AlgorithmHolder> allOperators = new TreeSet<>();
private static HashMap<String, AlgorithmHolder> operatorMaps = new HashMap<>();
static {
registerDefault();
}
@SuppressWarnings("unchecked")
private static void registerDefault() {
ClassScanner.AnnotationClassVisitor visitor = new ClassScanner.AnnotationClassVisitor(OpKey.class);
ClassScanner.scan(visitor, Lists.newArrayList("com.virjar.sipsoup.parse.expression.operator"));
Set<Class> classSet = visitor.getClassSet();
for (Class clazz : classSet) {
if (AlgorithmUnit.class.isAssignableFrom(clazz)) {
addOperator(clazz);
}
}
}
public static void addOperator(String key, int priority, Class<? extends AlgorithmUnit> algorithmUnit) {
if ("#".equals(key)) {
throw new IllegalStateException("\"#\" can not to be register a operator,please contact author virjar@virjar.com"))
;
}
AlgorithmHolder holder = new AlgorithmHolder(algorithmUnit, key, priority);
allOperators.add(holder);
operatorMaps.put(key, holder);
}
public static void addOperator(Class<? extends AlgorithmUnit> algorithmUnitClass) {
OpKey annotation = algorithmUnitClass.getAnnotation(OpKey.class);
if (annotation == null) {
throw new IllegalStateException("can not register operator for class " + algorithmUnitClass
+ ",such can not resolve operator name");
}
String key = annotation.value();
if (StringUtils.isBlank(key)) {
throw new IllegalStateException(
"can not register operator for class " + algorithmUnitClass + " ,such operator name is empty");
}
addOperator(key, annotation.priority(), algorithmUnitClass);
}
public static AlgorithmUnit createByName(String operatorName) {
AlgorithmHolder holder = operatorMaps.get(operatorName);
return ObjectFactory.newInstance(holder.aClass);
}
public static int judgePriority(String operatorName) {
if ("#".equals(operatorName)) {
// 这是一个特殊逻辑,运算栈需要有一个兜底判断的操作符,所以#是RPN默认的一个运算符,但是他不会表现在编译好的语法树里面
return Integer.MIN_VALUE;
}
AlgorithmHolder holder = operatorMaps.get(operatorName);
return holder.priority;
}
public static synchronized List<AlgorithmHolder> allAlgorithmUnitList() {
return Lists.newCopyOnWriteArrayList(allOperators);
}
public static class AlgorithmHolder implements Comparable<AlgorithmHolder> {
@Getter
private String key;
@Getter
private Class<? extends AlgorithmUnit> aClass;
private int priority;
public AlgorithmHolder(Class<? extends AlgorithmUnit> aClass, String key, int priority) {
this.aClass = aClass;
this.key = key;
this.priority = priority;
}
@Override
public int compareTo(AlgorithmHolder o) {
String thisKey = key;
String otherKey = o.key;
if (thisKey.length() != otherKey.length()) {
return otherKey.length() - thisKey.length();
}
return thisKey.compareTo(otherKey);
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
AlgorithmHolder that = (AlgorithmHolder) o;
return key != null ? key.equals(that.key) : that.key == null;
}
@Override
public int hashCode() {
return key != null ? key.hashCode() : 0;
}
}
}
package com.virjar.superappium.xpath.parser.expression;
import com.virjar.superappium.ViewImage;
public interface SyntaxNode {
Object calc(ViewImage viewImage);
}
package com.virjar.superappium.xpath.parser.expression.node;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
public abstract class AlgorithmUnit implements SyntaxNode {
protected SyntaxNode left = null;
protected SyntaxNode right = null;
public void setLeft(SyntaxNode left) {
this.left = left;
}
public void setRight(SyntaxNode right) {
this.right = right;
}
}
package com.virjar.superappium.xpath.parser.expression.node;
import com.virjar.superappium.ViewImage;
public abstract class BooleanRevertUnit extends WrapperUnit {
@Override
public Object calc(ViewImage element) {
return !((Boolean) wrap().calc(element));
}
}
package com.virjar.superappium.xpath.parser.expression.node;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.function.filter.FilterFunction;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import java.util.List;
public class FunctionNode implements SyntaxNode {
private FilterFunction filterFunction;
private List<SyntaxNode> filterFunctionParams;
public FunctionNode(FilterFunction filterFunction, List<SyntaxNode> filterFunctionParams) {
this.filterFunction = filterFunction;
this.filterFunctionParams = filterFunctionParams;
}
@Override
public Object calc(ViewImage viewImage) {
return filterFunction.call(viewImage, filterFunctionParams);
}
}
package com.virjar.superappium.xpath.parser.expression.node;
import com.virjar.superappium.xpath.parser.expression.OperatorEnv;
public abstract class WrapperUnit extends AlgorithmUnit {
private AlgorithmUnit delegate = null;
protected abstract String targetName();
protected AlgorithmUnit wrap() {
if (delegate == null) {
delegate = OperatorEnv.createByName(targetName());
delegate.setLeft(left);
delegate.setRight(right);
}
return delegate;
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
import java.math.BigDecimal;
/**
* Created by virjar on 17/6/10.
*
* @author virjar
* @since 0.0.1 加法运算
*/
@OpKey(value = "+", priority = 20)
public class AddUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
return XpathUtil.toPlainString(leftValue) + XpathUtil.toPlainString(rightValue);
}
// 左右都不为空,开始计算
// step one think as number
if (leftValue instanceof Number && rightValue instanceof Number) {
// 都是整数,则执行整数加法
if (leftValue instanceof Integer && rightValue instanceof Integer) {
return (Integer) leftValue + (Integer) rightValue;
}
// 包含小数,转double执行加法
if (leftValue instanceof Double || rightValue instanceof Double || leftValue instanceof Float
|| rightValue instanceof Float) {
return ((Number) leftValue).doubleValue() + ((Number) rightValue).doubleValue();
}
// 包含BigDecimal 转bigDecimal
if (leftValue instanceof BigDecimal || rightValue instanceof BigDecimal) {
return XpathUtil.toBigDecimal((Number) leftValue).add(XpathUtil.toBigDecimal((Number) rightValue));
}
// 包含长整数,且不包含小数,全部转化为长整数计算
if (leftValue instanceof Long || rightValue instanceof Long) {
return ((Number) leftValue).longValue() + ((Number) rightValue).longValue();
}
// 兜底,用double执行计算
return ((Number) leftValue).doubleValue() + ((Number) rightValue).doubleValue();
}
// 有一方不是数字,转化为字符串进行链接
return XpathUtil.toPlainString(leftValue) + XpathUtil.toPlainString(rightValue);
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.WrapperUnit;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "and", priority = 0)
public class And2Unit extends WrapperUnit {
@Override
protected String targetName() {
return "&&";
}
@Override
public Object calc(ViewImage element) {
return wrap().calc(element);
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "&&", priority = 0)
public class AndUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
return Boolean.FALSE;
}
// 左右都不为空,开始计算
// step one think as number
if (leftValue instanceof Boolean && rightValue instanceof Boolean) {
return (Boolean) leftValue && (Boolean) rightValue;
}
return Boolean.FALSE;
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "*=", priority = 10)
public class ContainUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
return Boolean.FALSE;
}
return XpathUtil.toPlainString(leftValue).contains(XpathUtil.toPlainString(rightValue));
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.exception.EvaluateException;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
import java.math.BigDecimal;
/**
* Created by virjar on 17/6/10.
*
* @author virjar
* @since 0.0.1 除法运算
*/
@OpKey(value = "/", priority = 30)
public class DivideUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
throw new EvaluateException("operate is null,left: " + leftValue + " right:" + rightValue);
}
// 左右都不为空,开始计算
// step one think as number
if (leftValue instanceof Number && rightValue instanceof Number) {
// 都是整数,则执行整数除法
if (leftValue instanceof Integer && rightValue instanceof Integer) {
return (Integer) leftValue / (Integer) rightValue;
}
// 包含小数,转double执行除法
if (leftValue instanceof Double || rightValue instanceof Double || leftValue instanceof Float
|| rightValue instanceof Float) {
return ((Number) leftValue).doubleValue() / ((Number) rightValue).doubleValue();
}
// 包含BigDecimal 转bigDecimal
if (leftValue instanceof BigDecimal || rightValue instanceof BigDecimal) {
if (leftValue instanceof BigDecimal && rightValue instanceof BigDecimal) {
return ((BigDecimal) leftValue).divide((BigDecimal) rightValue, BigDecimal.ROUND_HALF_UP);// 默认四舍五入
}
BigDecimal newLeft = XpathUtil.toBigDecimal((Number) leftValue);
BigDecimal newRight = XpathUtil.toBigDecimal((Number) rightValue);
return newLeft.divide(newRight, BigDecimal.ROUND_HALF_UP);
}
// 包含长整数,且不包含小数,全部转化为长整数计算
if (leftValue instanceof Long || rightValue instanceof Long) {
return ((Number) leftValue).longValue() / ((Number) rightValue).longValue();
}
// 兜底,用double执行计算
return ((Number) leftValue).doubleValue() / ((Number) rightValue).doubleValue();
}
throw new EvaluateException(
"divide operate must with number parameter left:" + leftValue + " right:" + rightValue);
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "$=", priority = 10)
public class EndWithUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
return Boolean.FALSE;
}
return XpathUtil.toPlainString(leftValue).endsWith(XpathUtil.toPlainString(rightValue));
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "=", priority = 10)
public class EqualUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null && rightValue == null) {
return Boolean.TRUE;
}
if (leftValue == null || rightValue == null) {
return Boolean.FALSE;
}
return leftValue.equals(rightValue);
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.xpath.parser.expression.node.BooleanRevertUnit;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = ">=", priority = 10)
public class GreaterEqualUnit extends BooleanRevertUnit {
@Override
protected String targetName() {
return "<";
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
/**
* Created by virjar on 17/6/10.
*
* @author virjar
* @since 0.0.1 大于> 运算
*/
@OpKey(value = ">", priority = 10)
public class GreaterThanUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
return XpathUtil.toPlainString(leftValue).compareTo(XpathUtil.toPlainString(rightValue)) > 0;
}
// 左右都不为空,开始计算
// step one think as number
if (leftValue instanceof Number && rightValue instanceof Number) {
return ((Number) leftValue).doubleValue() > ((Number) rightValue).doubleValue();
}
return XpathUtil.toPlainString(leftValue).compareTo(XpathUtil.toPlainString(rightValue)) > 0;
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.xpath.parser.expression.node.BooleanRevertUnit;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "<=", priority = 10)
public class LessEqualUnit extends BooleanRevertUnit {
@Override
protected String targetName() {
return ">";
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "<", priority = 10)
public class LessThanUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
return XpathUtil.toPlainString(rightValue).compareTo(XpathUtil.toPlainString(rightValue)) < 0;
}
// 左右都不为空,开始计算
// step one think as number
if (leftValue instanceof Number && rightValue instanceof Number) {
return ((Number) leftValue).doubleValue() < ((Number) rightValue).doubleValue();
}
return XpathUtil.toPlainString(leftValue).compareTo(XpathUtil.toPlainString(rightValue)) < 0;
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.exception.EvaluateException;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
import java.math.BigDecimal;
/**
* Created by virjar on 17/6/10.
*
* @author virjar
* @since 0.0.1 减法运算
*/
@OpKey(value = "-", priority = 20)
public class MinusUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
throw new EvaluateException("operate is null,left: " + leftValue + " right:" + rightValue);
}
// 左右都不为空,开始计算
// step one think as number
if (leftValue instanceof Number && rightValue instanceof Number) {
// 都是整数,则执行整数除法
if (leftValue instanceof Integer && rightValue instanceof Integer) {
return (Integer) leftValue - (Integer) rightValue;
}
// 包含小数,转double执行除法
if (leftValue instanceof Double || rightValue instanceof Double || leftValue instanceof Float
|| rightValue instanceof Float) {
return ((Number) leftValue).doubleValue() - ((Number) rightValue).doubleValue();
}
// 包含BigDecimal 转bigDecimal
if (leftValue instanceof BigDecimal || rightValue instanceof BigDecimal) {
if (leftValue instanceof BigDecimal && rightValue instanceof BigDecimal) {
return ((BigDecimal) leftValue).subtract((BigDecimal) rightValue);
}
BigDecimal newLeft = XpathUtil.toBigDecimal((Number) leftValue);
BigDecimal newRight = XpathUtil.toBigDecimal((Number) rightValue);
return newLeft.subtract(newRight);
}
// 包含长整数,且不包含小数,全部转化为长整数计算
if (leftValue instanceof Long || rightValue instanceof Long) {
return ((Number) leftValue).longValue() - ((Number) rightValue).longValue();
}
// 兜底,用double执行计算
return ((Number) leftValue).doubleValue() - ((Number) rightValue).doubleValue();
}
throw new EvaluateException(
"minus operate must with number parameter left:" + leftValue + " right:" + rightValue);
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.exception.EvaluateException;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
import java.math.BigDecimal;
/**
* Created by virjar on 17/6/10.
*
* @author virjar
* @since 0.0.1 乘法运算
*/
@OpKey(value = "*", priority = 30)
public class MultiUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
throw new EvaluateException("operate is null,left: " + leftValue + " right:" + rightValue);
}
// 左右都不为空,开始计算
// step one think as number
if (leftValue instanceof Number && rightValue instanceof Number) {
// 都是整数,则执行整数除法
if (leftValue instanceof Integer && rightValue instanceof Integer) {
return (Integer) leftValue * (Integer) rightValue;
}
// 包含小数,转double执行除法
if (leftValue instanceof Double || rightValue instanceof Double || leftValue instanceof Float
|| rightValue instanceof Float) {
return ((Number) leftValue).doubleValue() * ((Number) rightValue).doubleValue();
}
// 包含BigDecimal 转bigDecimal
if (leftValue instanceof BigDecimal || rightValue instanceof BigDecimal) {
if (leftValue instanceof BigDecimal && rightValue instanceof BigDecimal) {
return ((BigDecimal) leftValue).multiply((BigDecimal) rightValue);
}
BigDecimal newLeft = XpathUtil.toBigDecimal((Number) leftValue);
BigDecimal newRight = XpathUtil.toBigDecimal((Number) rightValue);
return newLeft.multiply(newRight);
}
// 包含长整数,且不包含小数,全部转化为长整数计算
if (leftValue instanceof Long || rightValue instanceof Long) {
return ((Number) leftValue).longValue() * ((Number) rightValue).longValue();
}
// 兜底,用double执行计算
return ((Number) leftValue).doubleValue() * ((Number) rightValue).doubleValue();
}
throw new EvaluateException(
"multiply operate must with number parameter left:" + leftValue + " right:" + rightValue);
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.xpath.parser.expression.node.BooleanRevertUnit;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "!=", priority = 10)
public class NotEqualUnit extends BooleanRevertUnit {
@Override
protected String targetName() {
return "=";
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.xpath.parser.expression.node.BooleanRevertUnit;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "!~", priority = 10)
public class NotMatchUnit extends BooleanRevertUnit {
@Override
protected String targetName() {
return "~=";
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by virjar on 17/6/10.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface OpKey {
/**
* 操作符标志,xpath解析器会根据当前的字符是否是这个标记,决定使用对应的处理器进行运算
*
* @return 对应符号标记,如"+","-","*","/","%",">","<",">=",">=","!="
*/
String value();
int priority();
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.WrapperUnit;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "or", priority = 0)
public class Or2Unit extends WrapperUnit {
@Override
protected String targetName() {
return "||";
}
@Override
public Object calc(ViewImage element) {
return wrap().calc(element);
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "||", priority = 0)
public class OrUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
// 左边为true,右边不管是啥,都为真
if (leftValue != null && leftValue instanceof Boolean && (Boolean) leftValue) {
return true;
}
// 左边不为真,以右边为主
if (rightValue != null && rightValue instanceof Boolean && (Boolean) rightValue) {
return true;
}
return Boolean.FALSE;
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "~=", priority = 10)
public class RegexUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
return Boolean.FALSE;
}
return XpathUtil.toPlainString(leftValue).matches(XpathUtil.toPlainString(rightValue));
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.exception.EvaluateException;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
import java.math.BigDecimal;
/**
* Created by virjar on 17/6/10.
*
* @author virjar
* @since 0.0.1 模数运算
*/
@OpKey(value = "%", priority = 30)
public class RemainderUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
throw new EvaluateException("operate is null,left: " + leftValue + " right:" + rightValue);
}
// 左右都不为空,开始计算
// step one think as number
if (leftValue instanceof Number && rightValue instanceof Number) {
// 都是整数,则执行整数除法
if (leftValue instanceof Integer && rightValue instanceof Integer) {
return (Integer) leftValue % (Integer) rightValue;
}
// 包含小数,转double执行除法
if (leftValue instanceof Double || rightValue instanceof Double || leftValue instanceof Float
|| rightValue instanceof Float) {
return ((Number) leftValue).doubleValue() % ((Number) rightValue).doubleValue();
}
// 包含BigDecimal 转bigDecimal
if (leftValue instanceof BigDecimal || rightValue instanceof BigDecimal) {
if (leftValue instanceof BigDecimal && rightValue instanceof BigDecimal) {
return ((BigDecimal) leftValue).remainder((BigDecimal) rightValue);
}
BigDecimal newLeft = XpathUtil.toBigDecimal((Number) leftValue);
BigDecimal newRight = XpathUtil.toBigDecimal((Number) rightValue);
return newLeft.remainder(newRight);
}
// 包含长整数,且不包含小数,全部转化为长整数计算
if (leftValue instanceof Long || rightValue instanceof Long) {
return ((Number) leftValue).longValue() % ((Number) rightValue).longValue();
}
// 兜底,用double执行计算
return ((Number) leftValue).doubleValue() % ((Number) rightValue).doubleValue();
}
throw new EvaluateException(
"remainder operate must with number parameter left:" + leftValue + " right:" + rightValue);
}
}
package com.virjar.superappium.xpath.parser.expression.operator;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.node.AlgorithmUnit;
import com.virjar.superappium.xpath.util.XpathUtil;
/**
* Created by virjar on 17/6/10.
*/
@OpKey(value = "^=", priority = 10)
public class StartWithUnit extends AlgorithmUnit {
@Override
public Object calc(ViewImage element) {
Object leftValue = left.calc(element);
Object rightValue = right.calc(element);
if (leftValue == null || rightValue == null) {
return Boolean.FALSE;
}
return XpathUtil.toPlainString(leftValue).startsWith(XpathUtil.toPlainString(rightValue));
}
}
各运算符优先级定义
+ :20 加法运算
- :20 减法运算
* :30 乘法运算
/ :30 除法运算
% :30 取模运算
&& :0 逻辑且运算
|| :0 逻辑或运算
and :0 逻辑且运算,等价于&&
or :0 逻辑或运算,等价于||
= :10 相等判断,逻辑运算
> :10 大于,逻辑运算
< :10 小于,逻辑运算
>= :10 大于等于,逻辑运算
<= :10 小于等于,逻辑运算
*= :10 包含,测试表达式左侧数据是否包含表达式右侧数据,仅适用于字符串,逻辑运算
$= :10 以xxx结尾,测试左侧数据是否以表达式右侧数据结尾,仅适用于字符串,逻辑运算
^= :10 以xxx开始,测试左侧数据是否以表达式右侧数据开始,仅适用于字符串,逻辑运算
!= :10 不等于,和"="作用相反,逻辑运算
~= :10 模式匹配,测试左侧数据是否符合右侧字符串代表的正则表达式模式,仅适用于字符串,逻辑运算
!~ :10 不匹配,与"~="相反,如果左侧数据不匹配右侧字符串代表的正则表达式,则返回true
package com.virjar.superappium.xpath.parser.expression.token;
public class Token {
public static final String OPERATOR = "OPERATOR";
public static final String CONSTANT = "CONSTANT";
public static final String NUMBER = "NUMBER";
public static final String EXPRESSION = "EXPRESSION";
public static final String ATTRIBUTE_ACTION = "ATTRIBUTE_ACTION";
public static final String XPATH = "XPATH";
public static final String FUNCTION = "FUNCTION";
public static final String BOOLEAN = "BOOLEAN";
}
package com.virjar.superappium.xpath.parser.expression.token;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.consumer.AttributeActionConsumer;
import com.virjar.superappium.xpath.parser.expression.token.consumer.BooleanConsumer;
import com.virjar.superappium.xpath.parser.expression.token.consumer.DefaultWordConsumer;
import com.virjar.superappium.xpath.parser.expression.token.consumer.DefaultXpathConsumer;
import com.virjar.superappium.xpath.parser.expression.token.consumer.DigitConsumer;
import com.virjar.superappium.xpath.parser.expression.token.consumer.ExpressionConsumer;
import com.virjar.superappium.xpath.parser.expression.token.consumer.FunctionConsumer;
import com.virjar.superappium.xpath.parser.expression.token.consumer.OperatorConsumer;
import com.virjar.superappium.xpath.parser.expression.token.consumer.StringConstantConsumer;
import com.virjar.superappium.xpath.parser.expression.token.consumer.XpathConsumer;
import com.virjar.superappium.xpath.parser.expression.token.handler.AttributeHandler;
import com.virjar.superappium.xpath.parser.expression.token.handler.BooleanHandler;
import com.virjar.superappium.xpath.parser.expression.token.handler.ConstantHandler;
import com.virjar.superappium.xpath.parser.expression.token.handler.ExpressionHandler;
import com.virjar.superappium.xpath.parser.expression.token.handler.FunctionHandler;
import com.virjar.superappium.xpath.parser.expression.token.handler.NumberHandler;
import com.virjar.superappium.xpath.parser.expression.token.handler.XpathHandler;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
public class TokenAnalysisRegistry {
private static TreeSet<TokenConsumerWrapper> allConsumer = new TreeSet<>();
private static Map<String, TokenHandler> allHandler = new HashMap<>();
static {
registerHandler(new AttributeHandler());
registerHandler(new BooleanHandler());
registerHandler(new ConstantHandler());
registerHandler(new FunctionHandler());
registerHandler(new NumberHandler());
registerHandler(new XpathHandler());
registerHandler(new ExpressionHandler());
registerConsumer(new OperatorConsumer());// 40 指定字符开头 div(23) 可以理解为一个函数,也可以理解为一个除法运算,这种歧义不解决了
registerConsumer(new DigitConsumer());// 50 数字开头
registerConsumer(new FunctionConsumer());// 60 identify开头,紧随左括号,和一般字母可能冲突
registerConsumer(new BooleanConsumer());// 70 true,false
// 下面的token不会冲突
registerConsumer(new AttributeActionConsumer());// 10 @开头
registerConsumer(new StringConstantConsumer());// 30 单号开头
registerConsumer(new XpathConsumer());// 20 反引号开头
registerConsumer(new ExpressionConsumer());// 0 括号开头
// TODO
registerConsumer(new DefaultWordConsumer());
registerConsumer(new DefaultXpathConsumer());
}
public static void registerHandler(TokenHandler tokenHandler) {
if (Token.OPERATOR.equals(tokenHandler.typeName()) && allHandler.containsKey(Token.OPERATOR)) {
throw new IllegalStateException(
"can not register operator handler,operator handler must hold by framework");
}
allHandler.put(tokenHandler.typeName(), tokenHandler);
}
/**
* @param tokenConsumer token识别器
* @see OperatorEnv#addOperator(java.lang.String, int, java.lang.Class)
*/
public static void registerConsumer(TokenConsumer tokenConsumer) {
// operator是特殊逻辑,他应该由系统解析,外部不能知道如何构建语法树,所以操作符的语法节点管理权由框架持有,
// 第三方如需扩展,可以通过扩展操作符的方式,注册操作符的运算逻辑即可
if (!Token.OPERATOR.equals(tokenConsumer.tokenType()) && !allHandler.containsKey(tokenConsumer.tokenType())) {
throw new IllegalStateException("can not register token consumer ,not token handler available");
}
allConsumer.add(new TokenConsumerWrapper(tokenConsumer));
}
public static TokenHandler findHandler(String tokenType) {
return allHandler.get(tokenType);
}
public static Iterable<? extends TokenConsumer> consumerIterable() {
return allConsumer;
}
private static class TokenConsumerWrapper implements Comparable<TokenConsumer>, TokenConsumer {
private TokenConsumer delegate;
TokenConsumerWrapper(TokenConsumer delegate) {
this.delegate = delegate;
}
@Override
public String consume(TokenQueue tokenQueue) {
return delegate.consume(tokenQueue);
}
@Override
public int order() {
return delegate.order();
}
@Override
public String tokenType() {
return delegate.tokenType();
}
@Override
public int compareTo(TokenConsumer o) {
if (this == o) {
return 0;
}
return Integer.valueOf(delegate.order()).compareTo(o.order());
}
}
}
\ No newline at end of file
package com.virjar.superappium.xpath.parser.expression.token;
import com.virjar.superappium.xpath.parser.TokenQueue;
public interface TokenConsumer {
String consume(TokenQueue tokenQueue);
int order();
String tokenType();
}
package com.virjar.superappium.xpath.parser.expression.token;
import com.virjar.superappium.xpath.exception.XpathSyntaxErrorException;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
public interface TokenHandler {
SyntaxNode parseToken(String tokenStr) throws XpathSyntaxErrorException;
String typeName();
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
public class AttributeActionConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
if (tokenQueue.matches("@")) {
tokenQueue.advance();
return tokenQueue.consumeAttributeKey();
}
return null;
}
@Override
public int order() {
return 10;
}
@Override
public String tokenType() {
return Token.ATTRIBUTE_ACTION;
}
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
public class BooleanConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
if (tokenQueue.matchesBoolean()) {
return tokenQueue.consumeWord();
}
return null;
}
@Override
public int order() {
return 70;
}
@Override
public String tokenType() {
return Token.BOOLEAN;
}
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
public class DefaultWordConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
if (tokenQueue.matchesWord()) {
return tokenQueue.consumeWord();
}
return null;
}
@Override
public int order() {
return 90;
}
@Override
public String tokenType() {
return Token.CONSTANT;
}
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.util.StringUtils;
import com.virjar.superappium.xpath.XpathParser;
import com.virjar.superappium.xpath.exception.XpathSyntaxErrorException;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
public class DefaultXpathConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
String s = tokenQueue.tryConsumeTo(" ");
if (StringUtils.isEmpty(s)) {
return null;
}
try {
XpathParser.compile(s);
return tokenQueue.consumeTo(" ");
} catch (XpathSyntaxErrorException e) {
// log.debug("exception when compile xpath:{}", s, e);
// TODO
// ignore,根据约定,如果发生异常,则忽略本次调用
return null;
}
}
@Override
public int order() {
return 80;
}
@Override
public String tokenType() {
return Token.XPATH;
}
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
public class DigitConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
// 当前遇到的串是一个数字
if (tokenQueue.matchesDigit()) {
return tokenQueue.consumeDigit();
}
return null;
}
@Override
public int order() {
return 50;
}
@Override
public String tokenType() {
return Token.NUMBER;
}
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
public class ExpressionConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
// 当前遇到的串是一个括号
if (tokenQueue.matches("(")) {
// 括号优先级,单独处理,不在逆波兰式内部处理括号问题了,这样逻辑简单一些,而且也浪费不了太大的计算消耗
return tokenQueue.chompBalanced('(', ')');
}
return null;
}
@Override
public int order() {
return 0;
}
@Override
public String tokenType() {
return Token.EXPRESSION;
}
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
public class FunctionConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
if (tokenQueue.matchesFunction()) {
return tokenQueue.consumeFunction();
}
return null;
}
@Override
public int order() {
return 60;
}
@Override
public String tokenType() {
return Token.FUNCTION;
}
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.OperatorEnv;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
import java.util.List;
public class OperatorConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
List<OperatorEnv.AlgorithmHolder> algorithmHolders = OperatorEnv.allAlgorithmUnitList();
for (OperatorEnv.AlgorithmHolder holder : algorithmHolders) {
if (tokenQueue.matches(holder.getKey())) {
tokenQueue.consume(holder.getKey());
return holder.getKey();
}
}
return null;
}
@Override
public int order() {
return 40;
}
@Override
public String tokenType() {
return Token.OPERATOR;
}
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
public class StringConstantConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
if (tokenQueue.matches("\'")) {
return TokenQueue.unescape(tokenQueue.chompBalanced('\'', '\''));
} else if (tokenQueue.matches("\"")) {
return TokenQueue.unescape(tokenQueue.chompBalanced('\"', '\"'));
}
return null;
}
@Override
public int order() {
return 30;
}
@Override
public String tokenType() {
return Token.CONSTANT;
}
}
package com.virjar.superappium.xpath.parser.expression.token.consumer;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenConsumer;
public class XpathConsumer implements TokenConsumer {
@Override
public String consume(TokenQueue tokenQueue) {
// xpath子串
if (tokenQueue.matches("`")) {
return tokenQueue.chompBalanced('`', '`');
}
return null;
}
@Override
public int order() {
return 20;
}
@Override
public String tokenType() {
return Token.XPATH;
}
}
package com.virjar.superappium.xpath.parser.expression.token.handler;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenHandler;
public class AttributeHandler implements TokenHandler {
@Override
public SyntaxNode parseToken(final String tokenStr) {
return element -> element.attribute(tokenStr);
}
@Override
public String typeName() {
return Token.ATTRIBUTE_ACTION;
}
}
package com.virjar.superappium.xpath.parser.expression.token.handler;
import com.virjar.superappium.util.Lists;
import com.virjar.superappium.xpath.exception.XpathSyntaxErrorException;
import com.virjar.superappium.xpath.function.FunctionEnv;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import com.virjar.superappium.xpath.parser.expression.node.FunctionNode;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenHandler;
public class BooleanHandler implements TokenHandler {
@Override
public SyntaxNode parseToken(final String tokenStr) throws XpathSyntaxErrorException {
return new FunctionNode(FunctionEnv.getFilterFunction(BooleanUtils.toBoolean(tokenStr) ? "true" : "false"),
Lists.<SyntaxNode> newLinkedList());
}
@Override
public String typeName() {
return Token.BOOLEAN;
}
}
package com.virjar.superappium.xpath.parser.expression.token.handler;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenHandler;
public class ConstantHandler implements TokenHandler {
@Override
public SyntaxNode parseToken(final String tokenStr) {
return new SyntaxNode() {
@Override
public Object calc(ViewImage element) {
return tokenStr;
}
};
}
@Override
public String typeName() {
return Token.CONSTANT;
}
}
package com.virjar.superappium.xpath.parser.expression.token.handler;
import com.virjar.superappium.xpath.exception.XpathSyntaxErrorException;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.ExpressionParser;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenHandler;
/**
* Created by virjar on 17/6/12.
*/
public class ExpressionHandler implements TokenHandler {
@Override
public SyntaxNode parseToken(String tokenStr) throws XpathSyntaxErrorException {
return new ExpressionParser(new TokenQueue(tokenStr)).parse();
}
@Override
public String typeName() {
return Token.EXPRESSION;
}
}
package com.virjar.superappium.xpath.parser.expression.token.handler;
import com.virjar.superappium.xpath.exception.XpathSyntaxErrorException;
import com.virjar.superappium.xpath.parser.TokenQueue;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenHandler;
public class FunctionHandler implements TokenHandler {
@Override
public SyntaxNode parseToken(String tokenStr) throws XpathSyntaxErrorException {
return new FunctionParser(new TokenQueue(tokenStr)).parse();
}
@Override
public String typeName() {
return Token.FUNCTION;
}
}
package com.virjar.superappium.xpath.parser.expression.token.handler;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.util.StringUtils;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenHandler;
public class NumberHandler implements TokenHandler {
@Override
public SyntaxNode parseToken(final String tokenStr) {
return new SyntaxNode() {
@Override
public Object calc(ViewImage element) {
if (StringUtils.contains(tokenStr, ".")) {
return NumberUtils.toDouble(tokenStr);
} else {
return NumberUtils.toInt(tokenStr);
}
}
\
};
}
@Override
public String typeName() {
return Token.NUMBER;
}
}
package com.virjar.superappium.xpath.parser.expression.token.handler;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.XpathParser;
import com.virjar.superappium.xpath.exception.XpathSyntaxErrorException;
import com.virjar.superappium.xpath.model.XNode;
import com.virjar.superappium.xpath.model.XNodes;
import com.virjar.superappium.xpath.model.XpathEvaluator;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import com.virjar.superappium.xpath.parser.expression.token.Token;
import com.virjar.superappium.xpath.parser.expression.token.TokenHandler;
public class XpathHandler implements TokenHandler {
@Override
public SyntaxNode parseToken(String tokenStr) throws XpathSyntaxErrorException {
final XpathEvaluator xpathEvaluator = new XpathParser(tokenStr).parse();
return new SyntaxNode() {
@Override
public Object calc(ViewImage element) {
return xpathEvaluator.evaluate(new XNodes(XNode.e(element)));
}
};
}
@Override
public String typeName() {
return Token.XPATH;
}
}
package com.virjar.superappium.xpath.util;
import com.virjar.superappium.ViewImage;
import com.virjar.superappium.xpath.exception.EvaluateException;
import com.virjar.superappium.xpath.model.XNode;
import com.virjar.superappium.xpath.parser.expression.SyntaxNode;
import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.List;
public class XpathUtil {
public static List<ViewImage> transformToElement(List<XNode> input) {
List<ViewImage> ret = new LinkedList<>();
for (XNode xNode : input) {
if (!xNode.isText()) {
ret.add(xNode.getElement());
}
}
return ret;
}
public static String toPlainString(Object obj) {
if (obj == null) {
return "null";
}
return obj.toString();
}
public static BigDecimal toBigDecimal(Number number) {
if (number instanceof BigDecimal) {
return (BigDecimal) number;
}
if (number instanceof Integer) {
return new BigDecimal(number.intValue());
}
if (number instanceof Double || number instanceof Float) {// BigDecimal float 也是转double
return new BigDecimal(number.doubleValue());
}
if (number instanceof Long) {
return BigDecimal.valueOf(number.longValue());
}
return new BigDecimal(number.toString());
}
public static Integer firstParamToInt(List<SyntaxNode> params, ViewImage element, String functionName) {
if (params.size() > 0) {
Object calc = params.get(0).calc(element);
if (calc != null && !(calc instanceof Integer)) {
throw new EvaluateException(functionName + " parameter must be integer");
} else {
if (calc != null) {
return (Integer) calc;
}
}
}
return null;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment