一.背景和目标
尝试开发一个通用go_jsonpath库(code.byted.org/temai/go\_j…
-
Get/MGet:指定节点元素value的查询
-
Set:指定节点元素value的插入
-
Delete:指定节点元素value的删除
-
Sort:指定节点元素列表的排序
二.Json库现状
调研当前一些常见json lib,没有找到比较理想的,详细如下:
lib | 说明 | example |
---|---|---|
encoding/json | Go内建的 JSON 编码解码(序列化反序列化) | - |
josephburnett/jd/lib | json diff | |
oliveagle/jsonpath | 基于JSONPath的节点元素查询 | |
tidwall/sjson | 基于自定义的 dot syntax语法,对指定节点元素的value进行set操作。 | { "name": {"first": "Tom", "last": "Anderson"}, "age":37, "children": ["Sara","Alex","Jack"], "fav.movie": "Deer Hunter", "friends": [ {"first": "James", "last": "Murphy"}, {"first": "Roger", "last": "Craig"} ] } |
三.go_jsonpath
go_jsonpath(code.byted.org/temai/go\_j…
3.1 jsonpath介绍
JSONPath 之于 JSON,就如 XPath 之于 XML。JSONPath 可以方便对 JSON 数据结构进行内容提取(goessner.net/articles/Js…
比如,下面Json
{ "store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{ "category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{ "category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
对应的jsonpath:
3.2 规则引擎govaluate介绍
规则引擎govaluate与 JavaScript 中的eval功能类似,用于计算任意表达式的值,详细用法参考github.com/Knetic/gova…
func main() {
expr, _ := govaluate.NewEvaluableExpression("foo > 0")
parameters := make(map[string]interface{})
parameters["foo"] = -1
result, _ := expr.Evaluate(parameters)
fmt.Println(result)
expr, _ = govaluate.NewEvaluableExpression("(requests_made * requests_succeeded / 100) >= 90")
parameters = make(map[string]interface{})
parameters["requests_made"] = 100
parameters["requests_succeeded"] = 80
result, _ = expr.Evaluate(parameters)
fmt.Println(result)
expr, _ = govaluate.NewEvaluableExpression("(mem_used / total_mem) * 100")
parameters = make(map[string]interface{})
parameters["total_mem"] = 1024
parameters["mem_used"] = 512
result, _ = expr.Evaluate(parameters)
fmt.Println(result)
}
3.3 go_jsonpath介绍
- 接口介绍
方法 | 用法 | 说明 |
---|---|---|
get | Get(path string) (val interface{}, err error) | 获取指定jsonpath |
set | Set(path string, value interface{}) (err error) | 更改指定jsonpath,key不存在时自动创建 |
delete | Delete(path string) (err error) | 删除指定jsonpath |
extract | Extract(path string, extractType ExtractTypeEnum) (err error) | 将复杂jsonpath值(url/json等)展开成结构化数据 |
ab_delete | abDelete() (err error) | 两个结构相同json匹配某种规则时,删除指定jsonpath |
- 详细用法
比如,下面json
{
"promotions":[
{
"product_id":"123",
"type":1
},
{
"product_id":"456",
"type":2
}
],
"extra":{
"logid":"20000000000000000000000000"
},
"entries":[
{
"title":"咨询",
"type":1
},
{
"title":"订单",
"type":2
}
],
"status_code":0,
"status_msg":""
}
处理逻辑
func TestGoJsonPath_Executor(t *testing.T) {
ctx := context.Background()
jf, err := os.Open(FromJson)
if err != nil {
t.Fatal(err.Error())
}
jv, err := ioutil.ReadAll(jf)
if err != nil {
t.Fatal(err.Error())
}
h, err := executor.NewExecutor(ctx, string(jv))
if err != nil {
t.Fatal(err.Error())
}
// 1. Set,Get
_ = h.Set("$.promotions[0].product_id", "5")
val, _ := h.Get("$.promotions[0].product_id")
assert.Equal(t, val, "5")
// 2. Sort,MGet
_ = h.Sort("$.entries", "get([v1], 'type') > get([v2], 'type')")
_, vals := h.MGet("$.entries[*].type")
assert.Equal(t, vals[0].(float64) > vals[1].(float64), true)
// 3. Delete
val, _ = h.Get("$.extra.logid")
assert.Equal(t, val, "20000000000000000000000000")
_ = h.Delete("$.extra.logid")
val, _ = h.Get("$.extra.logid")
assert.Equal(t, val, nil)
}