[关闭]
@aliasliyu4 2016-12-15T15:55:05.000000Z 字数 3472 阅读 6481

十分钟教你写一个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{}类型意味这可以存储任何类型的数据。

  1. type Js struct {
  2. data interface{}
  3. }

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

  1. func NewJson(data string) *Js {
  2. j := new(Js)
  3. var f interface{}
  4. err := json.Unmarshal([]byte(data), &f)
  5. if nil != err {
  6. return j
  7. }
  8. j.data = f
  9. return j
  10. }

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

  1. // return map in Go
  2. func (j *Js) GetMapData() map[string]interface{} {
  3. if m, ok := (j.data).(map[string]interface{}); ok {
  4. return m
  5. }
  6. return nil
  7. }

获取key对应的value

  1. // Acoording to the key of the returned data information , return js.data
  2. // if you know json is an object
  3. func (j *Js) Get(key string) *Js {
  4. m := j.GetMapData()
  5. if v, ok := m[key]; ok {
  6. j.data = v
  7. return j
  8. }
  9. j.data = nil
  10. return j
  11. }

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

  1. // GetIndex get []interface or map in Go
  2. func (j *Js) GetIndex(i int) *Js {
  3. num := i - 1
  4. if m, ok := (j.data).([]interface{}); ok {
  5. if num <= len(m)-1{
  6. v := m[num]
  7. j.data = v
  8. }else{
  9. j.data = nil
  10. }
  11. return j
  12. }
  13. {
  14. if m, ok := (j.data).(map[string]interface{}); ok {
  15. var n = 0
  16. var data = make(map[string]interface{})
  17. for i, v := range m {
  18. if n == num {
  19. switch vv := v.(type) {
  20. case float64:
  21. data[i] = strconv.FormatFloat(vv, 'f', -1, 64)
  22. j.data = data
  23. return j
  24. case string:
  25. data[i] = vv
  26. j.data = data
  27. return j
  28. case []interface{}:
  29. j.data = vv
  30. return j
  31. }
  32. }
  33. n++
  34. }
  35. }
  36. }
  37. j.data = nil
  38. return j
  39. }

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

  1. // The data must be []interface{}, According to your custom number to return key adn array data
  2. func (j *Js) GetKey(key string, i int) (*Js, error) {
  3. num := i - 1
  4. if i > len((j.data).([]interface{})) {
  5. return nil, errors.New("index out of range list")
  6. }
  7. if m, ok := (j.data).([]interface{}); ok {
  8. v := m[num].(map[string]interface{})
  9. if h, ok := v[key]; ok {
  10. j.data = h
  11. return j, nil
  12. }
  13. }
  14. j.data = nil
  15. return j, nil
  16. }

递归map

  1. // According to the custom of the PATH to fing element
  2. // You can use function this to find recursive map
  3. func (j *Js) GetPath(args ...string) *Js {
  4. d := j
  5. for i := range args {
  6. m := d.GetMapData()
  7. if val, ok := m[args[i]]; ok {
  8. d.data = val
  9. } else {
  10. d.data = nil
  11. return d
  12. }
  13. }
  14. return d
  15. }

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

  1. // String return string
  2. func (j *Js) String() string {
  3. if m, ok := j.data.(string); ok {
  4. return m
  5. }
  6. if m, ok := j.data.(float64); ok {
  7. return strconv.FormatFloat(m, 'f', -1, 64)
  8. }
  9. return ""
  10. }

返回key和value数组 []string

  1. func (j *Js) ToArray() (k, d []string) {
  2. var key, data []string
  3. if m, ok := (j.data).([]interface{}); ok {
  4. for _, value := range m {
  5. for index, v := range value.(map[string]interface{}) {
  6. switch vv := v.(type) {
  7. case float64:
  8. data = append(data, strconv.FormatFloat(vv, 'f', -1, 64))
  9. key = append(key, index)
  10. case string:
  11. data = append(data, vv)
  12. key = append(key, index)
  13. }
  14. }
  15. }
  16. return key, data
  17. }
  18. if m, ok := (j.data).(map[string]interface{}); ok {
  19. for index, v := range m {
  20. switch vv := v.(type) {
  21. case float64:
  22. data = append(data, strconv.FormatFloat(vv, 'f', -1, 64))
  23. key = append(key, index)
  24. case string:
  25. data = append(data, vv)
  26. key = append(key, index)
  27. }
  28. }
  29. return key, data
  30. }
  31. return nil, nil
  32. }

返回一个[]string

  1. // Array return array
  2. func (j *Js) Array() ([]string, error) {
  3. if a, ok := (j.data).([]interface{}); ok {
  4. array := make([]string, 0)
  5. for _, v := range a {
  6. switch vv := v.(type) {
  7. case float64:
  8. array = append(array, strconv.FormatFloat(vv, 'f', -1, 64))
  9. case string:
  10. array = append(array, vv)
  11. }
  12. }
  13. return array, nil
  14. }
  15. return nil, errors.New("type assertion to []interface{} failed")
  16. }

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

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

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

参考

RFC4627
Json in Go

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注