snack - JsonPath 扩展定制
1、操作符定制参考
示例:
public class OperatorDemo {
public static void main(String[] args) {
//::定制操作符
OperatorLib.register("startsWith", (ctx, node, term) -> {
ONode leftNode = term.getLeftNode(ctx, node);
if (leftNode.isString()) {
ONode rightNode = term.getRightNode(ctx, node);
if (rightNode.isNull()) {
return false;
}
return leftNode.getString().startsWith(rightNode.getString());
}
return false;
});
//::检验效果
assert ONode.ofJson("{'list':['a','b','c']}")
.select("$.list[?@ startsWith 'a']")
.size() == 1;
}
}
了解接口 Operator 接口和参数:
package org.noear.snack4.jsonpath;
import org.noear.snack4.ONode;
import org.noear.snack4.jsonpath.filter.Term;
public interface Operator {
boolean apply(QueryContext ctx, ONode node, Term term);
}
参数 | 描述 |
---|---|
ctx | 查询上下文 |
node | 当前节点 |
term | 逻辑项描述(左操作元,操作符?,右操作元?) |
2、扩展函数定制参考:
函数(或扩展函数)有两种用途(使用同一个接口开发):
- 过滤函数,用在过滤器中。
- 聚合函数,用在选择器中。
示例(本示例定制的函数可作: 过滤函数 或 聚合函数 使用):
package org.noear.snack4.jsonpath;
import org.noear.snack4.ONode;
import org.noear.snack4.jsonpath.FunctionLib;
import org.noear.snack4.jsonpath.JsonPathException;
public class FunctionDemo {
public static void main(String[] args) {
//::定制 floor 函数
FunctionLib.register("floor", (ctx, argNodes) -> {
ONode arg0 = argNodes.get(0);
if (ctx.isDescendant()) {
for (ONode n1 : arg0.getArray()) {
if (n1.isNumber()) {
n1.setValue(Math.floor(n1.getDouble()));
}
}
return arg0;
} else {
ONode n1 = arg0.get(0);
if (n1.isNumber()) {
return ctx.newNode(Math.floor(n1.getDouble()));
} else {
return ctx.newNode();
}
}
});
//::检验效果
//作 聚合函数 用 //out: 1.0
System.out.println(ONode.ofJson("{'a':1,'b':2}")
.select("$.a.floor()")
.toJson());
//作 过滤函数 用 //out: 2.0 //(在 IETF 规范里以子项进行过滤,即 1,2)
System.out.println(ONode.ofJson("{'a':1,'b':2}")
.select("$[?floor(@) > 1].first()")
.toJson());
}
}
了解接口 Func 接口和参数:
package org.noear.snack4.jsonpath;
import org.noear.snack4.ONode;
import java.util.List;
@FunctionalInterface
public interface Function {
ONode apply(QueryContext ctx, List<ONode> currentNodes, List<ONode> argNodes);
}
参数 | 描述 | |
---|---|---|
ctx | 查询上下文 | |
currentNodes | 当前节点 | 作为过滤函数用时,此值为 null |
argNodes | 参数节点(如果有参数声明) |
3、查询上下文 QueryContext
QueryContext 对整个查询定制工作极为重要:hasStandard 可以检查,使用侧添加了什么标准要求?isInFilter 可以知道当前运行是否在过滤器内?getMode 可以知道当前是什么模式,查询?生成?删除?
public interface QueryContext {
/**
* 有使用标准?
*
*/
boolean hasStandard(Standard standard);
/**
* 是否为多输出
*
*/
boolean isMultiple();
/**
* 是否在过滤器中
*
*/
boolean isInFilter();
/**
* 查询根节点
*
*/
ONode getRoot();
/**
* 查询模式
*
*/
QueryMode getMode();
/**
* 获取根选项配置
*
*/
Options getOptions();
/**
* 获取节点的子节点
*/
ONode getChildNodeBy(ONode node, String key);
/**
* 获取节点的子节点
*/
ONode getChildNodeAt(ONode node, int idx);
/**
* 缓存获取
*/
<T> T cacheIfAbsent(String key, Function<String, ?> mappingFunction);
/**
* 内嵌查询(`@.user.name`)
*/
ONode nestedQuery(ONode target, JsonPath query);
}