Solon v3.6.4

snack - JsonPath 扩展定制

</> markdown

1、查询上下文的关键属性(与定制相关)

属性描述备注
isMultiple是否为多节点输出前面执行过 ..x*[?]。通过 fun() 聚合后重置为 false
isExpanded是否已展开前面执行过 ..x*
isDescendant是否有后代前面执行过 ..x

查询时,接口输入的是一个节点(内部会变成一个单节点的节点列表),通过执行过 ..x(展开后代) 或 *(展开子代) 或 [?](用子代过滤) 片段后,会变成多节点的节点列表。即 isMultiple==true

使用 ..x* 时,会展开后代或子代。即 isExpanded==true

使用 ..x 时,会展开后代,即有后代了 isDescendant==true

2、操作符定制参考

示例:

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;

@FunctionalInterface
public interface Operator {
    /**
     * 应用
     *
     * @param ctx  查询上下文
     * @param node 目标节点
     * @param term 逻辑表达式项
     */
    boolean apply(QueryContext ctx, ONode node, Term term);
}
参数描述
ctx查询上下文
node当前节点
term逻辑项描述(左操作元,操作符?,右操作元?)。同时支持一元、二元、三元操作的描述

3、扩展函数定制参考:

函数(或扩展函数)有两种用途(使用同一个接口开发):

  • 过滤函数,用在过滤器中。
  • 聚合函数,用在选择器中。

示例(本示例定制的函数可作: 过滤函数 或 聚合函数 使用):

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) {
        //定制 length 函数(已预置)
        FunctionLib.register("length", (ctx, argNodes) -> {
            if (argNodes.size() != 1) {
                throw new JsonPathException("Requires 1 parameters");
            }

            ONode arg0 = argNodes.get(0); //节点列表(选择器的结果)

            if (ctx.isMultiple()) {
                return ctx.newNode(arg0.getArray().size());
            } else {
                if (arg0.getArray().size() > 0) {
                    ONode n1 = arg0.get(0);

                    if (n1.isArray()) return ctx.newNode(n1.getArray().size());
                    if (n1.isObject()) return ctx.newNode(n1.getObject().size());

                    if (ctx.hasFeature(Feature.JsonPath_JaywayMode) == false) {
                        if (n1.isString()) return ctx.newNode(n1.getString().length());
                    }
                }

                return ctx.newNode();
            }
        });

        //检验效果//out: 3
        System.out.println(ONode.ofJson("[1,2,3]")
                .select("$.length()")
                .toJson());
    }
}

了解接口 Function 接口和参数:

package org.noear.snack4.jsonpath;

import org.noear.snack4.ONode;
import java.util.List;

@FunctionalInterface
public interface Function {
    /**
     * 应用
     *
     * @param ctx      查询上下文
     * @param argNodes 参数节点列表
     */
    ONode apply(QueryContext ctx, List<ONode> argNodes);
}

参数描述
ctx查询上下文
argNodes参数节点列表

3、查询上下文 QueryContext

QueryContext 对整个查询定制工作极为重要:hasFeature 可以检查特性?getMode 可以知道当前是什么模式(查询,生成,删除)?等。

public interface QueryContext {
    /**
     * 有使用标准?
     */
    boolean hasFeature(Feature feature);

    /**
     * 是否为多输出
     */
    boolean isMultiple();

    /**
     * 是否为已展开
     */
    boolean isExpanded();

    /**
     * 是否有后代选择
     */
    boolean isDescendant();

    /**
     * 查询根节点
     */
    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`)
     */
    QueryResult nestedQuery(ONode target, JsonPath query);

    /**
     * 新建节点
     */
    default ONode newNode() {
        return new ONode(getOptions());
    }

    /**
     * 新建节点
     */
    default ONode newNode(Object value) {
        return new ONode(getOptions(), value);
    }
}