Golang库的使用(一):gabs

298 阅读3分钟

背景

golang处理json,标注使用encoding/json库去Unmarshal,然后用map[string]interface{}等解决,其中需要各种数据类型强转,没有那么方便。gabs作用就是可以直接用path寻找对应结构,也可以通过path构造新的json。

可达鸭.jpeg

介绍

Official description:Gabs is a small utility for dealing with dynamic or unknown JSON structures in Go. It's pretty much just a helpful wrapper for navigating hierarchies of map[string]interface{} objects provided by the encoding/json package. It does nothing spectacular apart from being fabulous.

Get gabs

go get -u github.com/Jeffail/gabs

Parse Json

Common Parse
// +build ignore

package main

import "github.com/Jeffail/gabs"

/*
   @func: gabs的库测试使用
   @author: Andy_文铎
   @time: 2021/11/18
 */

func main() {
   s := `{
   "outter":{
      "inner":{
         "value1":10,
         "value2":22
      },
      "alsoInner":{
         "value1":20,
         "array1":[
            30, 40
         ]
      }
   }
}`
   parseJson(s)
}

func parseJson(s string) {
   jsonParsed, err := gabs.ParseJSON([]byte(s))
   if err != nil {
      panic(err)
   }

   var value float64
   var ok bool

   value, ok = jsonParsed.Path("outter.inner.value1").Data().(float64)
   // value == 10.0, ok == true

   value, ok = jsonParsed.Search("outter", "inner", "value1").Data().(float64)
   // value == 10.0, ok == true

   value, ok = jsonParsed.Search("outter", "alsoInner", "array1", "1").Data().(float64)
   // value == 40.0, ok == true

   gObj, err := jsonParsed.JSONPointer("/outter/alsoInner/array1/1")
   if err != nil {
      panic(err)
   }
   value, ok = gObj.Data().(float64)
   // value == 40.0, ok == true

   value, ok = jsonParsed.Path("does.not.exist").Data().(float64)
   // value == 0.0, ok == false

   exists := jsonParsed.Exists("outter", "inner", "value1")
   // exists == true

   exists = jsonParsed.ExistsP("does.not.exist")
   // exists == false
}

通常先用

jsonParsed, err :=gabs.ParseJSON([]byte(s))

获取一个*gabs.Container,接着用

data := jsonParsed.Path(path).Data()

获取对应path下边的数据data,最后可以根据需要对data进行数据强转

Parse Object

对于这个官方有很多种方式, 第一种:

// 把array的索引镶嵌在path里
jsonParsed, err := gabs.ParseJSON([]byte(`{"array":[{"value":1},{"value":2},{"value":3}]}`))
if err != nil {
	panic(err)
}
fmt.Println(jsonParsed.Path("array.1.value").String())

第二种:

// 使用Children()
jsonParsed, err := gabs.ParseJSON([]byte(`{"array":["first","second","third"]}`))
if err != nil {
	panic(err)
}

for _, child := range jsonParsed.S("array").Children() {
	fmt.Println(child.Data().(string))
}

这种测试使用了一下,当array的元素比较多的时候会有问题,具体原因还不清楚,所以array中object比较大的时候不建议使用

第三种:

// 使用ArrayElementP, 获取某path下的array某个索引的内容
// 获取array的数量
count, err := jsonParsed.ArrayCountP("detail.pois")
fmt.Println("count->", count)
con, err := jsonParsed.ArrayElementP(0, "detail.pois")
fmt.Println("con->", con)

这种不会出现第二种的问题,个人通常使用这种方式获取array的数据

New Json

新建*gabs.Container, 并写入

// 把数据data写入对应path
jsonObj := gabs.New()
jsonObj.SetP(data, "data.board.icon")

个人一般会封装一个函数,用来从一个json获取数据并赋值给新的json

// 从旧的Container到新的Container
func pathToNewPath(jsonParsed *gabs.Container, path string, jsonObj *gabs.Container, newPath string) {
   if jsonParsed.ExistsP(path) {
      jsonObj.SetP(jsonParsed.Path(path).Data(), newPath)
   }
}

实例

// 解析数据
func parseMSData(content []byte) (string, error) {
   result := ""
   jsonParsed, err := gabs.ParseJSON(content)
   if err != nil {
      return result, err
   }
   jsonObj := gabs.New()

   con, err := jsonParsed.ArrayElementP(0, "xxx")
   if err != nil {
      return result, err
   }
   fmt.Println("conn data->", con.Data())

   poiPath, err := con.S("xxx").Children()
   if err != nil {
      return result, err
   }
   currentCity := ""
   for _, child := range poiPath {
      ctype := child.Path("ctype").Data().(float64)
      if ctype == 2 {
         currentCity = child.Path("cname").Data().(string)
      }
   }

   // sUid
   pathToNewPath(con, "uid", jsonObj, "data.tPOI.sUid")
   // sName
   pathToNewPath(con, "name", jsonObj, "data.tPOI.sName")
   // sAddr
   pathToNewPath(con, "addr", jsonObj, "data.tPOI.sAddr")
   // sPhone
   pathToNewPath(con, "phone", jsonObj, "data.tPOI.sPhone")
   // sShortAddr
   pathToNewPath(con, "short_addr", jsonObj, "data.tPOI.sShortAddr")
   // nCO
   pathToNewPath(con, "CO", jsonObj, "data.tPOI.nCO")

   // Cotype
   CO := con.Path("CO").Data().(string)
   jsonObj.SetP(fileconfig.GetConfig().CoType[CO], "data.tPOI.co_type")

   // richInfo
   pathToNewPath(con, "richInfo", jsonObj, "data.richInfo")

   // TT标签
   tags := getTTTags(con.Path("TT"), fileconfig.GetConfig().CoType[CO], CO)
   jsonObj.SetP(tags, "data.review_tags")

   // board
   bangdanIcon := "xxx"
   bgColor := "xxx"
   fontColor := "xxx"
   jsonObj.SetP(bangdanIcon, "data.board.icon")
   jsonObj.SetP(bgColor, "data.board.bgColor")
   jsonObj.SetP(fontColor, "data.board.fontColor")
   boardContent, err := con.ArrayElementP(0, "richInfo.deep.bangdan_new")
   pathToNewPath(boardContent, "ranklist_name", jsonObj, "data.board.name")
   pathToNewPath(boardContent, "poi_order", jsonObj, "data.board.rank")
   pathToNewPath(boardContent, "ranklist_id", jsonObj, "data.board.boardId")
   //boardContent := getGabsChild(con, "richInfo.deep.bangdan_new", 0)
   boardUrl := ""
   // do something to splice boardUrl
   if ranklist_id != "" && ranklist_name != "" {
      jsonObj.SetP(boardUrl, "data.board.boardUrl")
   }

   // indoor
   // floor_name
   pathToNewPath(con, "floor_name", jsonObj, "data.indoor.floor_name")
   // is_inside
   pathToNewPath(con, "is_inside", jsonObj, "data.indoor.is_inside")
   // inside_class
   pathToNewPath(con, "inside_class", jsonObj, "data.indoor.inside_class")
   // build_id
   pathToNewPath(con, "build_id", jsonObj, "data.indoor.build_id")
   // shinei_info.Bld_type

   // poiNote
   // PL
   // strNPLDescription

   // baseMapIconInfo
   // brand_id
   pathToNewPath(con, "brand_id", jsonObj, "data.brand_id")
   // brand_name
   pathToNewPath(con, "brand_name", jsonObj, "data.brand_name")


   // 加上err_msg和err_code
   jsonObj.SetP("ok", "err_msg")
   jsonObj.SetP(0, "err_code")
   return jsonObj.String(), nil
}

// 从旧的Container到新的Container
func pathToNewPath(jsonParsed *gabs.Container, path string, jsonObj *gabs.Container, newPath string) {
   if jsonParsed.ExistsP(path) {
      jsonObj.SetP(jsonParsed.Path(path).Data(), newPath)
   }
}

结语

在此mark一下gabs库的使用,亲测通过此库可以轻松解析json的path下的内容,甚至可以实现通过配置完成静态数据的旧结构到新结构的转换,后续有新的使用感悟再补充.