十分钟教你写一个 Json 解析库

fpdk4226 7年前
   <p>json是在开发当中一种常见的数据结构,本身它的协议栈就是很简洁的,如果有兴趣的同学,可以参考RFC4627文档,本文的最后我会附上这部分的链接,方便大家查看。那么在go项目的开发当中,比如最常见的web项目,我们需用到json来传递数据,那么必然就会面对将json object,转换成go中对应的数据结构的需求。无需担心的是,go提供了encoding/json解析包,我们接下来要做的工作就是在此基础上做一定封装,以方便自己使用。同时这个库也是特别适合新手来练手使用,因为它设计到了go中的map,struct,assert,interface{}...,所以对于加深对go基础的理解也很有帮助,甚至你还可以写出更好的呢!</p>    <p>项目地址: <a href="/misc/goto?guid=4959729859074905609" rel="nofollow,noindex">https://github.com/liyu4/ljson</a></p>    <h2>开始</h2>    <p>定义一个全局对象,data为interface{}类型意味这可以存储任何类型的数据。</p>    <pre>  <code class="language-go">typeJs struct {  datainterface{}  }  </code></pre>    <p>工厂模式实例化Js对象,这里我们将需要反序列化的data数据,先转换成byte数组, 然后将其解析到&f指向的值中,也就是说f是包含了我们反序列化得到的数据。本文接下来的部分就是对这个f的操作。</p>    <pre>  <code class="language-go">funcNewJson(datastring) *Js {  j:= new(Js)   varfinterface{}  err:=json.Unmarshal([]byte(data), &f)   if nil !=err{   returnj   }  j.data=f   returnj  }  </code></pre>    <p>获取map,这里我们使用了断言,判断interface{}是否是map[string]interface{}类型</p>    <pre>  <code class="language-go">// return map in Go  func(j*Js) GetMapData()map[string]interface{} {   ifm,ok:= (j.data).(map[string]interface{});ok{   returnm   }   return nil  }  </code></pre>    <p>获取key对应的value</p>    <pre>  <code class="language-go">// 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  }  </code></pre>    <p>或者value根据下标,这里指的是从slice和map中,你懂的,这里有一个点需要小心一下,就是map返回的顺序是不固定的</p>    <pre>  <code class="language-go">// 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  }  </code></pre>    <p>自定义key和下标返回value,注意错误的处理</p>    <pre>  <code class="language-go">// 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  }  </code></pre>    <p>递归map</p>    <pre>  <code class="language-go">// 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  }  </code></pre>    <p>String方法,相信大家也看到了我们的slice和map中的值都是interface{},转换陈string能方便我们的操作。</p>    <pre>  <code class="language-go">// 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 ""  }  </code></pre>    <p>返回key和value数组 []string</p>    <pre>  <code class="language-go">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  }  </code></pre>    <p>返回一个[]string</p>    <pre>  <code class="language-go">// 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")  }  </code></pre>    <p>一个漂亮但是没啥子用的调试函数</p>    <pre>  <code class="language-go">//for test  func(j*Js) Type() {  fmt.Println(reflect.TypeOf(j.data))  }  </code></pre>    <p>至此我们就完成了一个可以部署在生产环境中的json library,这个项目是小巧和坚实的,希望大家能自己动手写写,最好是在下雨的星期天下午。</p>    <h2>参考</h2>    <p><a href="/misc/goto?guid=4959729859181179201" rel="nofollow,noindex">RFC4627</a> <a href="/misc/goto?guid=4959729859262894630" rel="nofollow,noindex">Json in Go</a></p>    <p> </p>    <p>来自:https://www.zybuluo.com/aliasliyu4/note/601706</p>    <p> </p>