Solon v3.6.0

snack - JsonPath 扩展定制

</> markdown

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);
}