转载

十分钟教你写一个 json 解析库(Golang)

十分钟教你写一个json解析库(golang)

json是在开发当中一种常见的数据结构,本身它的协议栈就是很简洁的,如果有兴趣的同学,可以参考RFC4627文档,本文的最后我会附上这部分的链接,方便大家查看。那么在go项目的开发当中,比如最常见的web项目,我们需用到json来传递数据,那么必然就会面对将json object,转换成go中对应的数据结构的需求。无需担心的是,go提供了encoding/json解析包,我们接下来要做的工作就是在此基础上做一定封装,以方便自己使用。同时这个库也是特别适合新手来练手使用,因为它设计到了go中的map,struct,assert,interface{}...,所以对于加深对go基础的理解也很有帮助,甚至你还可以写出更好的呢!

项目地址: https://github.com/liyu4/ljson

开始

定义一个全局对象,data为interface{}类型意味这可以存储任何类型的数据。

typeJs struct {
datainterface{}
}

工厂模式实例化Js对象,这里我们将需要反序列化的data数据,先转换成byte数组, 然后将其解析到&f指向的值中,也就是说f是包含了我们反序列化得到的数据。本文接下来的部分就是对这个f的操作。

funcNewJson(datastring) *Js {
j:= new(Js)
 varfinterface{}
err:=json.Unmarshal([]byte(data), &f)
 if nil !=err{
 returnj
 }
j.data=f
 returnj
}

获取map,这里我们使用了断言,判断interface{}是否是map[string]interface{}类型

// return map in Go
func(j*Js) GetMapData()map[string]interface{} {
 ifm,ok:= (j.data).(map[string]interface{});ok{
 returnm
 }
 return nil
}

获取key对应的value

// Acoording to the key of the returned data information , return js.data
// if you know json is an object
func(j*Js) Get(keystring) *Js {
m:=j.GetMapData()
 ifv,ok:=m[key];ok{
j.data=v
 returnj
 }
j.data= nil
 returnj
}

或者value根据下标,这里指的是从slice和map中,你懂的,这里有一个点需要小心一下,就是map返回的顺序是不固定的

// GetIndex get []interface or map in Go
func(j*Js) GetIndex(iint) *Js {
num:=i- 1
 ifm,ok:= (j.data).([]interface{});ok{
 ifnum<=len(m)-1{
v:=m[num]
j.data=v
 }else{
j.data= nil
 }
 returnj
 }

 {
 ifm,ok:= (j.data).(map[string]interface{});ok{
 varn= 0
 vardata=make(map[string]interface{})
 fori,v:=range m{
 ifn==num{
 switchvv:=v.(type) {
 casefloat64:
data[i] =strconv.FormatFloat(vv, 'f', -1, 64)
j.data=data
 returnj
 case string:
data[i] =vv
j.data=data
 returnj
 case []interface{}:
j.data=vv
 returnj
 }
 }
n++
 }
 }
 }
j.data= nil
 returnj
}

自定义key和下标返回value,注意错误的处理

// The data must be []interface{}, According to your custom number to return key adn array data
func(j*Js) GetKey(keystring,iint) (*Js,error) {
num:=i- 1
 ifi>len((j.data).([]interface{})) {
 return nil,errors.New("index out of range list")
 }
 ifm,ok:= (j.data).([]interface{});ok{
v:=m[num].(map[string]interface{})
 ifh,ok:=v[key];ok{
j.data=h
 returnj, nil
 }
 }
j.data= nil
 returnj, nil
}

递归map

// According to the custom of the PATH to fing element
// You can use function this to find recursive map
func(j*Js) GetPath(args...string) *Js {
d:=j
 fori:=range args{
m:=d.GetMapData()

 ifval,ok:=m[args[i]];ok{
d.data=val
 } else {
d.data= nil
 returnd
 }
 }
 returnd
}

String方法,相信大家也看到了我们的slice和map中的值都是interface{},转换陈string能方便我们的操作。

// String return string
func(j*Js) String() string {
 ifm,ok:=j.data.(string);ok{
 returnm
 }
 ifm,ok:=j.data.(float64);ok{
 returnstrconv.FormatFloat(m, 'f', -1, 64)
 }
 return ""
}

返回key和value数组 []string

func(j*Js) ToArray() (k,d[]string) {
 varkey,data[]string
 ifm,ok:= (j.data).([]interface{});ok{
 for_,value:=range m{
 forindex,v:=range value.(map[string]interface{}) {
 switchvv:=v.(type) {
 casefloat64:
data=append(data,strconv.FormatFloat(vv, 'f', -1, 64))
key=append(key,index)
 case string:
data=append(data,vv)
key=append(key,index)
 }
 }
 }
 returnkey,data
 }
 ifm,ok:= (j.data).(map[string]interface{});ok{
 forindex,v:=range m{
 switchvv:=v.(type) {
 casefloat64:
data=append(data,strconv.FormatFloat(vv, 'f', -1, 64))
key=append(key,index)
 case string:
data=append(data,vv)
key=append(key,index)
 }
 }
 returnkey,data
 }
 return nil, nil
}

返回一个[]string

// Array return array
func(j*Js) Array() ([]string,error) {
 ifa,ok:= (j.data).([]interface{});ok{
array:=make([]string, 0)
 for_,v:=range a{
 switchvv:=v.(type) {
 casefloat64:
array=append(array,strconv.FormatFloat(vv, 'f', -1, 64))
 case string:
array=append(array,vv)
 }

 }
 returnarray, nil
 }
 return nil,errors.New("type assertion to []interface{} failed")
}

一个漂亮但是没啥子用的调试函数

//for test
func(j*Js) Type() {
fmt.Println(reflect.TypeOf(j.data))
}

至此我们就完成了一个可以部署在生产环境中的json library,这个项目是小巧和坚实的,希望大家能自己动手写写,最好是在下雨的星期天下午。

参考

RFC4627 Json in Go

原文  https://www.zybuluo.com/aliasliyu4/note/601706
正文到此结束
Loading...