基于JSONPath的Golang Json内容增删改查

一.背景和目标

尝试开发一个通用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 image
oliveagle/jsonpath 基于JSONPath的节点元素查询 image
tidwall/sjson 基于自定义的 dot syntax语法,对指定节点元素的value进行set操作。 image
{ "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)
}

猜你喜欢

转载自juejin.im/post/7120503723205328926