### 1、查询上下文的关键属性（与定制相关）



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

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


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

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


### 2、操作符定制参考

示例：

```java
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 接口和参数：

```java
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、扩展函数定制参考：

函数（或扩展函数）有两种用途（使用同一个接口开发）：

* 过滤函数，用在过滤器中。
* 聚合函数，用在选择器中。




示例（本示例定制的函数可作： 过滤函数 或 聚合函数 使用）：

```java
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 接口和参数：

```java
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 可以知道当前是什么模式（查询，生成，删除）？等。

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