# JSONPath **Repository Path**: vipkwds/jsonpath ## Basic Information - **Project Name**: JSONPath - **Description**: Go 语言实现的 JSONPath 工具,支持路径查询、设置、构建等操作 - **Primary Language**: Go - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-20 - **Last Updated**: 2026-05-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # JSONPath 工具 Go 语言实现的 JSONPath 工具,支持路径查询、设置、构建等操作。 ## 安装 ```bash go get gitee.com/vipkwds/jsonpath ``` ## 函数列表 ### 路径查询 | 函数 | 签名 | 说明 | |------|------|------| | `Get` | `Get(data interface{}, path string) (interface{}, error)` | 根据 JSONPath 获取值 | | `Getter[T]` | `Getter[T](data interface{}, path string) (T, error)` | 泛型获取,自动类型转换 | ### 路径设置 | 函数 | 签名 | 说明 | |------|------|------| | `Set` | `Set(path string, value any, baseData ...interface{}) (interface{}, error)` | 设置值 | | `Setter[T]` | `Setter[T](path string, value any, baseData ...interface{}) (T, error)` | 泛型设置值 | ### 路径构建 | 函数 | 签名 | 说明 | |------|------|------| | `ParsePath` | `ParsePath(path string) ([]Segment, error)` | 解析 JSONPath 为 Segments | | `BuildPathByNode` | `BuildPathByNode(data, node interface{}) (string, error)` | 通过节点对象查找路径 | | `BuildPathByKV` | `BuildPathByKV(data interface{}, key string, value any) ([]string, error)` | 通过键值查找所有匹配路径 | ### 数据解析 | 函数 | 签名 | 说明 | |------|------|------| | `ParseJSON` | `ParseJSON(jsonStr string) (interface{}, error)` | 解析 JSON 字符串 | ### 类型转换 | 函数 | 签名 | 说明 | |------|------|------| | `Decoder[T]` | `Decoder[T](inputData interface{}, path string, template *T) (T, error)` | JSONPath 结果解码绑定 | ### 批量写入 (Accumulator) | 函数 | 签名 | 说明 | |------|------|------| | `NewAccumulator` | `NewAccumulator() *Accumulator` | 创建累积器 | | `Accumulator.AddSmart` | `(a *Accumulator) AddSmart(sourcePath, targetPath, fieldType string, remoteData interface{}) error` | 智能添加,自动类型转换 | | `Accumulator.AddCallback` | `(a *Accumulator) AddCallback(sourcePath, targetPath string, convertFn func(sourceDataValue any, sourcePath, targetPath string) any, remoteData interface{}) error` | 回调添加,自定义转换 | | `Accumulator.AddBatch` | `(a *Accumulator) AddBatch(mappings []FieldMapping, remoteData interface{}) error` | 批量添加 | | `Accumulator.Build` | `(a *Accumulator) Build() map[string]interface{}` | 构建结果 | ### 类型定义 | 类型 | 定义 | 说明 | |------|------|------| | `Segment` | `type Segment struct { ... }` | JSONPath 解析后的路径段 | | `FilterExpr` | `type FilterExpr struct { ... }` | 过滤表达式 | | `SliceExpr` | `type SliceExpr struct { ... }` | 切片表达式 | | `FieldMapping` | `type FieldMapping struct { ... }` | 字段映射配置 | | `ConvertFn` | `type ConvertFn func(sourceDataValue any, sourcePath, targetPath string) (any, error)` | 自定义转换函数 | | `Accumulator` | `type Accumulator struct { ... }` | 批量写入累积器 | ### 错误变量 | 错误 | 说明 | |------|------| | `ErrInvalidPath` | 路径格式错误 | | `ErrPathNotFound` | 路径不存在 | | `ErrInvalidData` | 数据无效 | | `ErrTypeMismatch` | 类型不匹配 | ## 核心功能 ### 1. Get - 根据 JSONPath 获取值 ```go data := map[string]interface{}{ "name": "Alice", "age": 30, "items": []interface{}{ map[string]interface{}{"id": 1, "value": "a"}, map[string]interface{}{"id": 2, "value": "b"}, }, } // 获取简单值 name, _ := jsonpath.Get(data, "$.name") // "Alice" // 获取嵌套值 age, _ := jsonpath.Get(data, "$.items[0].value") // "a" ``` ### 2. Getter[T] - 泛型获取(类型安全) ```go // 获取值并自动转换类型 name, _ := jsonpath.Getter[string](data, "$.name") // string: "Alice" age, _ := jsonpath.Getter[int](data, "$.age") // int: 30 // 支持智能类型推导 // int/float/bool -> string 自动转换 s, _ := jsonpath.Getter[string](data, "$.age") // string: "30" // 数字类型互转 f, _ := jsonpath.Getter[float64](data, "$.age") // float64: 30 ``` ### 3. Set / Setter[T] - 设置值 ```go // 在现有数据中设置值 baseData := map[string]interface{}{ "info": map[string]interface{}{}, } result, _ := jsonpath.Set("$.info.name", "Bob", baseData) // result["info"]["name"] = "Bob" // 创建新结构(不传 baseData) newData, _ := jsonpath.Set("$.items[0].id", 100) // 自动构建完整的嵌套结构 // 泛型版本,自动类型转换 result, _ := jsonpath.Setter[map[string]interface{}]("$.user", map[string]interface{}{"name": "Alice"}) ``` ### 4. ParseJSON - JSON 字符串解析 ```go // 将 JSON 字符串解析为 interface{} data, err := jsonpath.ParseJSON(`{"name":"Alice","age":30}`) if err != nil { // invalid json } // 解析后可直接使用 Get/Getter/Set name, _ := jsonpath.Getter[string](data, "$.name") // "Alice" ``` ### 5. BuildPathByNode - 通过节点对象查找路径 ```go data := map[string]interface{}{ "users": []interface{}{ {"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}, }, } // 注意:node 必须是指针类型 target := data["users"].([]interface{})[0].(map[string]interface{}) path, _ := jsonpath.BuildPathByNode(data, &target) // path = "$.users[0]" ``` ### 6. BuildPathByKV - 通过键值对查找所有匹配路径 ```go data := map[string]interface{}{ "items": []interface{}{ map[string]interface{}{"type": "a", "value": 1}, map[string]interface{}{"type": "b", "value": 2}, map[string]interface{}{"type": "a", "value": 3}, }, } paths, _ := jsonpath.BuildPathByKV(data, "type", "a") // paths = ["$.items[0]", "$.items[2]"] ``` ### 7. Decoder[T any] - JSON 解码绑定 将 JSONPath 查询结果绑定到目标类型: ```go data, _ := jsonpath.ParseJSON(`{"items":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}`) // 解码为 []map[string]interface{} var result []map[string]interface{} result, _ = jsonpath.Decoder(data, "$.items", &result) // result = [{"name":"Alice","age":30},{"name":"Bob","age":25}] // 解码单个元素 var item map[string]interface{} item, _ = jsonpath.Decoder(data, "$.items[0]", &item) // item = {"name":"Alice","age":30} ``` ### 8. Accumulator - 批量 JSONPath 写入 Accumulator 用于批量累积写入多个字段映射,支持自动类型转换和自定义转换函数。 ```go // 创建累积器 acc := jsonpath.NewAccumulator() // 智能添加(自动类型转换) acc.AddSmart("$.code", "$.result.status", "int", remoteData) // 回调添加(自定义转换逻辑) acc.AddCallback("$.price", "$.amount", func(val, src, tgt string) any { f, _ := strconv.ParseFloat(val.(string), 64) return f * 100 }, remoteData) // 批量添加(支持 ConvertFn 优先于 FieldType) mappings := []jsonpath.FieldMapping{ {SourcePath: "$.code", TargetPath: "$.result.status", FieldType: "int"}, {SourcePath: "$.msg", TargetPath: "$.result.message", FieldType: "string"}, } acc.AddBatch(mappings, remoteData) // 构建结果 result := acc.Build() ``` ### FieldMapping 结构 | 字段 | 类型 | 说明 | |------|------|------| | `SourcePath` | string | JSONPath,从 remoteData 提取值 | | `TargetPath` | string | JSONPath,写入 result 的路径 | | `FieldType` | string | 类型标识符(int, float, string, bool 等) | | `Convert` | ConvertFn | 自定义转换函数,优先级最高 | ### ConvertFn 签名 ```go type ConvertFn func(sourceDataValue any, sourcePath, targetPath string) (any, error) ``` ### 类型转换优先级 1. **ConvertFn** - 如果设置了 Convert 字段,优先使用自定义转换 2. **FieldType** - 否则根据 FieldType 进行自动类型转换 3. **原样返回** - 如果都没有设置,使用原始值 ## JSONPath 语法 | 语法 | 说明 | 示例 | |------|------|------| | `$` | 根节点 | `Get(data, "$")` | | `.key` | 对象键 | `$.name` | | `[n]` | 数组索引 | `$.items[0]` | | `..key` | 递归下降 | `$..name`(查找所有 name) | | `[?(@.key==value)]` | 过滤表达式(支持 ==, !=, >, <, >=, <=) | `$.items[?(@.id>1)]` | | `[?(@.nested.key==value)]` | 嵌套属性过滤 | `$.items[?(@.config.type=='goods')]` | | `[?(@.key < $.other)]` | 内联引用过滤 | `$.list[?(@.price < $.expensive)]` | | `[*]` / `[]` | 通配符获取所有元素 | `$.list[*]` / `$.list[]` | | `[**]` | 展开合并嵌套数组 | `$.config.data[**]` | | `[start:end:step]` | 切片表达式, 索引 start 到 end(不含 end) | `$.items[1:3]` | | `.{field1\|rename1, field2}` | 字段映射/重命名 | `$.items.{brand, goodsId\|goods_id}` | ### 递归下降 `..` ```go data := map[string]interface{}{ "a": map[string]interface{}{ "b": map[string]interface{}{ "name": "deep", }, }, "name": "root", } names, _ := jsonpath.Get(data, "$..name") // ["root", "deep"] ``` ### 过滤表达式 `[?(@.key==value)]` ```go data := map[string]interface{}{ "items": []interface{}{ map[string]interface{}{"id": 1, "active": true}, map[string]interface{}{"id": 2, "active": false}, map[string]interface{}{"id": 3, "active": true}, }, } // 查找 active == true 的元素 activeItems, _ := jsonpath.Get(data, "$.items[?(@.active==true)]") // [map[id:1 active:true], map[id:3 active:true]] ``` ### 过滤表达式 - 比较运算符 支持 `>`, `<`, `>=`, `<=`, `!=` 比较运算符: ```go data, _ := jsonpath.ParseJSON(`{"list":[{"price":10},{"price":20},{"price":30}]}`) // price > 15 result, _ := jsonpath.Get(data, "$.list[?(@.price > 15)]") // [map[price:20], map[price:30]] // price <= 20 result, _ := jsonpath.Get(data, "$.list[?(@.price <= 20)]") // [map[price:10], map[price:20]] // price != 20 result, _ := jsonpath.Get(data, "$.list[?(@.price != 20)]") // [map[price:10], map[price:30]] ``` ### 过滤表达式 - 嵌套属性过滤 支持访问嵌套属性进行过滤(使用 `.` 分隔): ```go data := map[string]interface{}{ "config": []interface{}{ map[string]interface{}{"name": "slider", "data": []interface{}{}}, map[string]interface{}{"name": "goodsScroll", "config": map[string]interface{}{"type": "goods"}, "data": []interface{}{}}, map[string]interface{}{"name": "goodsGrid", "config": map[string]interface{}{"style": "grids"}, "data": []interface{}{}}, }, } // 过滤 config.type == "goods" result, _ := jsonpath.Get(data, "$.config[?(@.config.type=='goods')]") // [map[name:goodsScroll, config:map[type:goods], data:[]]] // 过滤 config.style == "grids" result, _ := jsonpath.Get(data, "$.config[?(@.config.style=='grids')]") // [map[name:goodsGrid, config:map[style:grids], data:[]]] ``` ### 过滤表达式 - 内联引用 支持在过滤表达式中引用其他字段(`[?(@.key < $.other)]`),并支持全部 6 个比较运算符:`==`, `!=`, `>`, `<`, `>=`, `<=` ```go data, _ := jsonpath.ParseJSON(`{"expensive": 25, "list":[{"price":10},{"price":20},{"price":30}]}`) // price < expensive (25) result, _ := jsonpath.Get(data, "$.list[?(@.price < $.expensive)]") // [map[price:10], map[price:20]] // price >= expensive (25) result, _ := jsonpath.Get(data, "$.list[?(@.price >= $.expensive)]") // [map[price:30]] // price == value data2, _ := jsonpath.ParseJSON(`{"value": 20, "list":[{"price":20},{"price":20},{"price":30}]}`) result, _ := jsonpath.Get(data2, "$.list[?(@.price == $.value)]") // [map[price:20], map[price:20]] // price != expensive result, _ := jsonpath.Get(data, "$.list[?(@.price != $.expensive)]") // [map[price:10], map[price:20], map[price:30]] ``` ### 通配符 `[*]` 和 `[]` 获取数组所有元素: ```go data, _ := jsonpath.ParseJSON(`{"list":[{"id":1},{"id":2},{"id":3}]}`) // $.list[*] result, _ := jsonpath.Get(data, "$.list[*]") // [map[id:1], map[id:2], map[id:3]] // $.list[] (效果相同) result, _ := jsonpath.Get(data, "$.list[]") // [map[id:1], map[id:2], map[id:3]] ``` ### 展开合并 `[**]` 当 JSONPath 返回嵌套数组时,使用 `[**]` 展开并合并为一个数组: ```go data := map[string]interface{}{ "config": []interface{}{ map[string]interface{}{"name": "page1", "data": []interface{}{{"id":1},{"id":2}}}, map[string]interface{}{"name": "page2", "data": []interface{}{{"id":3},{"id":4}}}, }, } // 不使用 [**] - 返回嵌套数组 result, _ := jsonpath.Get(data, "$.config.data") // [[map[id:1], map[id:2]], [map[id:3], map[id:4]]] // 使用 [**] - 展开合并为单个数组 result, _ := jsonpath.Get(data, "$.config.data[**]") // [map[id:1], map[id:2], map[id:3], map[id:4]] ``` **典型应用场景**:分页数据合并 ```go // 假设 config 中有多个 type=="goods" 的配置项,每个有自己的 data 数组 // 获取所有 type=="goods" 配置项的 data 并合并: result, _ := jsonpath.Get(data, "$.config[?(@.config.type=='goods')].data[**]") // 合并后的单个数组,包含所有商品 ``` ### 切片表达式 `[start:end:step]` ```go data := map[string]interface{}{ "items": []interface{}{1, 2, 3, 4, 5}, } // 索引 1 到 3(不含 3) sub1, _ := jsonpath.Get(data, "$.items[1:3]") // [2, 3] // 前两个元素 sub2, _ := jsonpath.Get(data, "$.items[:2]") // [1, 2] // 索引 3 之后的所有元素 sub3, _ := jsonpath.Get(data, "$.items[3:]") // [4, 5] // 每隔一个元素 sub4, _ := jsonpath.Get(data, "$.items[::2]") // [1, 3, 5] ``` ### 字段映射 `.{field1|rename1, field2}` 字段映射用于重命名字段或筛选需要的字段。语法:`.{源字段|新名字, 源字段, ...}` ```go data := map[string]interface{}{ "items": []interface{}{ map[string]interface{}{"brand": "Apple", "goodsId": "G001", "price": 100}, map[string]interface{}{"brand": "Samsung", "goodsId": "G002", "price": 200}, }, } // 映射字段:goodsId -> goods_id, price -> amount result, _ := jsonpath.Get(data, "$.items[**].{brand, goodsId|goods_id, price|amount}") // [ // map[brand:Apple goods_id:G001 amount:100], // map[brand:Samsung goods_id:G002 amount:200] // ] // 不重命名,只筛选字段 result, _ := jsonpath.Get(data, "$.items[**].{brand, goodsId}") // [ // map[brand:Apple goodsId:G001], // map[brand:Samsung goodsId:G002] // ] ``` **与 `[**]` 配合使用**: ```go // 常见场景:从分页配置中提取商品数据并重命名字段 data := map[string]interface{}{ "data": map[string]interface{}{ "config": []interface{}{ map[string]interface{}{ "config": map[string]interface{}{"type": "goods"}, "data": []interface{}{ map[string]interface{}{"brand": "Apple", "goodsId": "G001", "price": 100}, map[string]interface{}{"brand": "Samsung", "goodsId": "G002", "price": 200}, }, }, }, }, } // 获取 type=="goods" 配置下的所有商品,并映射字段 result, _ := jsonpath.Get(data, "$.data.config[?(@.config.type==\"goods\")].data[**].{brand, goodsId|goods_id, price|amount}") // 合并后的数组,包含重命名后的字段 ``` **缺失字段输出 `null`**:当源数据中不存在映射的字段时,输出 `null` 值: ```go data := map[string]interface{}{ "items": []interface{}{ map[string]interface{}{"brand": "Apple"}, // 没有 goodsId 和 price }, } result, _ := jsonpath.Get(data, "$.items[**].{brand, goodsId|goods_id, price|amount}") // [map[brand:Apple goods_id: amount:]] ``` ## 错误处理 ```go var ( ErrInvalidPath = errors.New("invalid jsonpath") // 路径格式错误 ErrPathNotFound = errors.New("path not found") // 路径不存在 ErrInvalidData = errors.New("invalid data") // 数据无效 ErrTypeMismatch = errors.New("type mismatch") // 类型不匹配 ) // 所有 API 都不会 panic val, err := jsonpath.Get(data, "$.nonexistent") if err != nil { fmt.Println(err) // path not found at segment 0 } ``` ## 泛型 Getter 类型转换规则 ```go // 支持的类型转换 jsonpath.Getter[int](data, "$.float_val") // float64 -> int jsonpath.Getter[float64](data, "$.int_val") // int -> float64 jsonpath.Getter[string](data, "$.int_val") // int -> string(智能推导) jsonpath.Getter[string](data, "$.bool_val") // bool -> string(智能推导) // 指针类型 jsonpath.Getter[*string](data, "$.name") // 返回 *string // 切片类型 jsonpath.Getter[[]interface{}](data, "$.arr") ``` ## nil 值处理 ```go data := map[string]interface{}{ "nilVal": nil, "nested": map[string]interface{}{ "nilVal": nil, }, } // nil 值不会报错,返回零值 val, err := jsonpath.Getter[string](data, "$.nilVal") // val = ""(string 的零值),err = nil ``` ## 输入数据格式 支持两种数据格式: ### 1. map[string]interface{} 直接使用 ```go data := map[string]interface{}{ "name": "Alice", "age": 30, } // 直接使用 Get/Getter/Set name, _ := jsonpath.Getter[string](data, "$.name") ``` ### 2. JSON 字符串自动解析 当传入 `string` 类型时,自动尝试解析为 JSON: ```go // 直接传入 JSON 字符串,无需先调用 ParseJSON name, _ := jsonpath.Getter[string](`{"name":"Alice","age":30}`, "$.name") // name = "Alice" // Get 也支持 result, _ := jsonpath.Get(`{"items":[{"id":1},{"id":2}]}`, "$.items[*]") // [map[id:1], map[id:2]] // Decoder 同样支持 var item map[string]interface{} jsonpath.Decoder(`{"name":"Alice"}`, "$.name", &item) ``` **注意**:如果字符串不是有效的 JSON,将返回错误。 ## 完整示例 ```go package main import ( "fmt" "gitee.com/vipkwds/jsonpath" ) func main() { data := map[string]interface{}{ "users": []interface{}{ {"name": "Alice", "age": 30, "active": true}, {"name": "Bob", "age": 25, "active": false}, {"name": "Carol", "age": 35, "active": true}, }, } // 获取所有活跃用户 activeUsers, _ := jsonpath.Get(data, "$.users[?(@.active==true)]") fmt.Printf("Active users: %v\n", activeUsers) // 获取用户数量(使用切片) users, _ := jsonpath.Getter[[]interface{}](data, "$.users") fmt.Printf("User count: %d\n", len(users)) // 查找特定用户路径 paths, _ := jsonpath.BuildPathByKV(data, "name", "Bob") fmt.Printf("Bob's paths: %v\n", paths) // 修改数据 updated, _ := jsonpath.Set("$.users[1].age", 26, data) fmt.Printf("Updated data: %v\n", updated) } ``` ## API 速查 | 函数 | 签名 | 说明 | |------|------|------| | `Get` | `Get(data, path) (interface{}, error)` | 获取 interface{} 值 | | `Getter[T]` | `Getter[T](data, path) (T, error)` | 获取泛型 T 值 | | `Set` | `Set(path, value, baseData...) (interface{}, error)` | 设置值 | | `Setter[T]` | `Setter[T](path, value, baseData...) (T, error)` | 泛型设置值 | | `ParseJSON` | `ParseJSON(jsonStr) (interface{}, error)` | 解析 JSON 字符串 | | `ParsePath` | `ParsePath(path) ([]Segment, error)` | 解析路径为 Segments | | `BuildPathByNode` | `BuildPathByNode(data, node) (string, error)` | 通过节点查找路径(指针匹配) | | `BuildPathByKV` | `BuildPathByKV(data, key, value) ([]string, error)` | 通过键值查找路径 | | `Decoder[T]` | `Decoder[T](data, path, template *T) (T, error)` | JSON 解码绑定 | | `NewAccumulator` | `NewAccumulator() *Accumulator` | 创建累积器 | | `AddSmart` | `AddSmart(sourcePath, targetPath, fieldType string, remoteData interface{}) error` | 智能添加 | | `AddCallback` | `AddCallback(sourcePath, targetPath string, convertFn func(...) any, remoteData interface{}) error` | 回调添加 | | `AddBatch` | `AddBatch(mappings []FieldMapping, remoteData interface{}) error` | 批量添加 |