直接把结构体编码成json数据

package main

import (
"encoding/json"
"fmt"
_ "os"
) type Address struct {
Type string
City string
Country string
} type Card struct {
Name string
Age int
Addresses []*Address
} func main() {
pa := &Address{"private", "Shanghai", "China"}
pu := &Address{"work", "Beijing", "China"}
c := Card{"Xin", 32, []*Address{pa, pu}} js, _ := json.Marshal(c)
fmt.Printf("Json: %s", js)
}

利用json.Marshal,可将结构体转为JSON数据:

Json: {"Name":"Xin","Age":32,"Addresses":[{"Type":"private","City":"Shanghai","Country":"China"},{"Type":"work","City":"Beijing","Country":"China"}]}

json.MarshalIndent(c, "", " ")可以将json代码格式化:

Json: {
"Name": "Xin",
"Age": 32,
"Addresses": [
{
"Type": "private",
"City": "Shanghai",
"Country": "China"
},
{
"Type": "work",
"City": "Beijing",
"Country": "China"
}
]
}

Tips

  1. 在 web 应用中最好使用json.MarshalforHTML()函数,会对数据执行HTML转码。
  2. map 的 key 必须是字符串类型。
  3. Channel,复杂类型和函数类型不能被编码。
  4. 指针可以被编码,实际上是对指针指向的值进行编码.

解码到数据结构

如果事先知道 JSON 数据的结构,可以事先定义一个结构来存储反序列化后的结果。如,对这样一段 json:

b := []byte(`{"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]}`)

我们定义这样一个数据结构:

type FamilyMember struct {
Name string
Age int
Parents []string
}

然后可以将其反序列化:

var m FamilyMember
err := json.Unmarshal(b, &m)

完整的程序:

package main

import (
"encoding/json"
"fmt"
) type FamilyMember struct {
Name string
Age int
Parents []string
} func main() {
b := []byte(`{"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]}`)
var m FamilyMember
// json.Unmarshal 用于解码 json 串
err := json.Unmarshal(b, &m)
if err == nil {
fmt.Printf("name: %s\nAge: %d\nParents: %v\n", m.Name, m.Age, m.Parents)
}
}

执行后输出:

name: Wednesday
Age: 6
Parents: [Gomez Morticia]

解码任意数据

json 包使用 map[string]interface{} 和 []interface{} 储存任意的 JSON 对象和数组。同样是上面的 JSON 串:

b := []byte(`{"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]}`)

用下面的代码进行解码:

var f interface{}
err := json.Unmarshal(b, &f)

会得到:

map[string]interface{} {
"Name": "Wednesday",
"Age": 6,
"Parents": []interface{} {
"Gomez",
"Morticia",
},
}

对于这类的数据,可以使用switch来判断节点的类型来遍历数据。



动态更改JSON Sprintf

Golang中使用 fmt.Sprintf 格式化 `JSON Data %s %d %f` 动态变更JSON数据.

其等效作用是, 采用struct转换, 更改结构体数据, 然后Marshal成JSON, 用于 http处理

JSON数据, 其中 %s 是占位符: 
  1. const jsonRes = `
  2. {
  3. "server": {
  4. "name": "ty",
  5. "imageRef": "f9436296-854f-4fe2-939d-eb667b245b78",
  6. "fmtSprintf": "%s",
  7. "max_count": 1,
  8. "min_count": 1,
  9. "networks": [
  10. {
  11. "uuid": "1e16b87f-ef66-4f0d-ba3d-d93234159076"
  12. }
  13. ],
  14. "metadata": {
  15. "ENV1": "100",
  16. "ENV2": "1000",
  17. "entrypoint": "/bin/sh -c 'while true; do echo hello world; sleep 99999d; done'"
  18. }
  19. }
  20. }
  21. `

使用 fmt.Sprintf  格式化内容, 注意Sprintf返回格式化结果, 需要赋值给变量使用:
  1. func fmtSprintfJson() error {
  2. //var datm map[string]interface{}
  3. var datm interface{}
  4. const jsonRes = `
  5. {
  6. "server": {
  7. "name": "ty",
  8. "imageRef": "f9436296-854f-4fe2-939d-eb667b245b78",
  9. "fmtSprintf": "%s",
  10. "max_count": 1,
  11. "min_count": 1,
  12. "networks": [
  13. {
  14. "uuid": "1e16b87f-ef66-4f0d-ba3d-d93234159076"
  15. }
  16. ],
  17. "metadata": {
  18. "ENV1": "100",
  19. "ENV2": "1000",
  20. "entrypoint": "/bin/sh -c 'while true; do echo hello world; sleep 99999d; done'"
  21. }
  22. }
  23. }
  24. `
  25. jsonResSprintf := fmt.Sprintf(jsonRes, "test")
  26. fmt.Println("jsonResSprintf = ", jsonResSprintf)
  27. err := json.Unmarshal([]byte(jsonResSprintf), &datm)
  28. if err != nil {
  29. fmt.Println("json.Unmarshal([]byte(json), createRequests) , Error : ", err)
  30. return err
  31. }
  32. fmt.Println("struct request = ", datm)
  33. return nil
  34. }



和 stream 中 JSON 打交道

上面所有的 JSON 数据来源都是预先定义的 []byte 缓存,在很多时候,如果能读取/写入其他地方的数据就好了。encoding/json 库中有两个专门处理这个事情的结构:Decoder和 Encoder

// Decoder 从 r io.Reader 中读取数据,`Decode(v interface{})` 方法把数据转换成对应的数据结构
func NewDecoder(r io.Reader) *Decoder // Encoder 的 `Encode(v interface{})` 把数据结构转换成对应的 JSON 数据,然后写入到 w io.Writer 中
func NewEncoder(w io.Writer) *Encoder

下面的例子就是从标准输入流中读取数据,解析成数据结构,删除所有键不是 Name 的字段,然后再 encode 成 JSON 数据,打印到标准输出。

package main

import (
"encoding/json"
"log"
"os"
) func main() {
dec := json.NewDecoder(os.Stdin)
enc := json.NewEncoder(os.Stdout)
for {
var v map[string]interface{}
if err := dec.Decode(&v); err != nil {
log.Println(err)
return
}
for k := range v {
if k != "Name" {
delete(v, k)
}
}
if err := enc.Encode(&v); err != nil {
log.Println(err)
}
}
}


更多控制:Tag

在定义 struct 字段的时候,可以在字段后面添加 tag,来控制 encode/decode 的过程:是否要 decode/encode 某个字段,JSON 中的字段名称是什么。

可以选择的控制字段有三种:

  • -:不要解析这个字段
  • omitempty:当字段为空(默认值)时,不要解析这个字段。比如 false、0、nil、长度为 0 的 array,map,slice,string
  • FieldName:当解析 json 的时候,使用这个名字

举例来说吧:

// 解析的时候忽略该字段。默认情况下会解析这个字段,因为它是大写字母开头的
Field int `json:"-"` // 解析(encode/decode) 的时候,使用 `other_name`,而不是 `Field`
Field int `json:"other_name"` // 解析的时候使用 `other_name`,如果struct 中这个值为空,就忽略它
Field int `json:"other_name,omitempty"`


延迟解析:json.RawMessage

在解析的时候,还可以把某部分先保留为 JSON 数据不要解析,等到后面得到更多信息的时候再去解析。继续拿 User 举例,比如我们要添加认证的信息,认证可以是用户名和密码,也可以是 token 认证。

type BasicAuth struct {
Email string
Password string
} type TokenAuth struct {
Token string
} type User struct {
Name string
IsAdmin bool
Followers uint
Auth json.RawMessage
}

我们在定义 User 结构体的时候,把认证字段的类型定义为 json.RawMessage,这样解析 JSON 数据的时候,对应的字段会先不急着转换成 Go 数据结构。然后我们可以自己去再次调用 Unmarshal 去读取里面的值:

  1. data := []byte(`{"Name":"cizixs","IsAdmin":true,"Followers":36}`)
  2. err := json.Unmarshal(data, &basicAuth)
  3. if basicAuth.Email != "" {
  4. // 这是用户名/密码认证方式,在这里继续做一些处理
  5. } else {
  6. json.Unmarshal(data, &tokenAuth)
  7. if tokenAuth.Token != "" {
  8. // 这是 token 认证方法
  9. }
  10. }

自定义解析方法

如果希望自己控制怎么解析成 JSON,或者把 JSON 解析成自定义的类型,只需要实现对应的接口(interface)。encoding/json 提供了两个接口:Marshaler 和 Unmarshaler

// Marshaler 接口定义了怎么把某个类型 encode 成 JSON 数据
type Marshaler interface {
MarshalJSON() ([]byte, error)
} // Unmarshaler 接口定义了怎么把 JSON 数据 decode 成特定的类型数据。如果后续还要使用 JSON 数据,必须把数据拷贝一份
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}

标准库 time.Time 就实现了这两个接口。另外一个简单的例子(这个例子来自于参考资料中 Go and JSON 文章):

type Month struct {
MonthNumber int
YearNumber int
} func (m Month) MarshalJSON() ([]byte, error){
return []byte(fmt.Sprintf("%d/%d", m.MonthNumber, m.YearNumber)), nil
} func (m *Month) UnmarshalJSON(value []byte) error {
parts := strings.Split(string(value), "/")
m.MonthNumber = strconv.ParseInt(parts[0], 10, 32)
m.YearNumber = strconv.ParseInt(parts[1], 10, 32) return nil
}









Golang JSON操作汇总的更多相关文章

  1. 分享基于.NET动态编译&Newtonsoft.Json封装实现JSON转换器(JsonConverter)原理及JSON操作技巧

    看文章标题就知道,本文的主题就是关于JSON,JSON转换器(JsonConverter)具有将C#定义的类源代码直接转换成对应的JSON字符串,以及将JSON字符串转换成对应的C#定义的类源代码,而 ...

  2. JSON资料汇总

    网络入门学习资料 1.W3School的JSON教程:http://www.w3school.com.cn/json/index.asp 2.Introducing JSON[介绍JSON]:http ...

  3. Json操作(DynamicJson)

    Json的简介 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了 ...

  4. ASP.NET 里的 JSON操作

    最近项目中需要用到 JSON操作,google了一下 找到了几个比较好的操作方法.... 一 .使用 mircosoft 提供的 .NET Framework 自带的 json操作方法 1. 使用Ja ...

  5. PHP数组操作汇总

    php 操作数组 (合并,拆分,追加,查找,删除等) - Just Code - ITeye技术网站 PHP操作数组的一些函数介绍 -- 简明现代魔法 PHP数组元素操作实例 -- 简明现代魔法 儿童 ...

  6. 提升效率的Linux终端快捷操作汇总

    很多普通 Linux 桌面用户都对使用终端感到排斥和恐惧,其实它没大家想的那么复杂,很多常见操作都可以直接在终端中进行,如:安装软件.升级系统等. 无论你是新手还是 Linux 终端使用的老鸟,系统极 ...

  7. Newtonsoft.Json 操作 JSON 字符串

    Newtonsoft.Json介绍 在做开发的时候,很多数据交换都是以json格式传输的.而使用Json的时候,我们很多时候会涉及到几个序列化对象的使用:DataContractJsonSeriali ...

  8. SQL字符串操作汇总

    SQL字符串操作汇总 --将字符串中从某个字符开始截取一段字符,然后将另外一个字符串插入此处 select stuff('hello,world!',4,4,'****')   --返回值hel*** ...

  9. Asp.Net Core 2.0 项目实战(8)Core下缓存操作、序列化操作、JSON操作等Helper集合类

    本文目录 1.  前沿 2.CacheHelper基于Microsoft.Extensions.Caching.Memory封装 3.XmlHelper快速操作xml文档 4.Serializatio ...

随机推荐

  1. Working With Push Buttons In Oracle Forms

    Managing push buttons at run time in Oracle Forms is very simple and in this tutorial you will learn ...

  2. 在Delphi中应用AOP实现日志功能

    AOP现在很火,网上有这许多支持AOP的框架,对于Delphi来说同样也有MeAOP.不过觉得这些框架太复杂了. 现在有一个系统,基本上都快结束了,整体上当然是没有采用什么AOP的框架.对于这样的系统 ...

  3. 【GLSL教程】(八)纹理贴图 【转】

    http://blog.csdn.net/racehorse/article/details/6664717 简单的纹理贴图(Simple Texture) 为了在GLSL中应用纹理,我们需要访问每个 ...

  4. 在程序中使用NV 3D Vision 【转】

    http://www.cnblogs.com/gongminmin/archive/2010/11/21/1883392.html 多年前NVIDIA就发布了3D Vision技术,能提供多种立体渲染 ...

  5. TRIZ系列-创新原理-20-有效作用的连续性原理

    有效作用的连续性原理表述例如以下:1)连续实施动作不要中断,物体的全部部分应该一直处于满负荷工作状态.2)去除全部空暇的,中间的动作:3)用循环的动作取代"来来回回"的动作: 这个 ...

  6. 获取服务器classes根路径

    /** * 获取web应用路径 * @Description : 方法描述 * @Method_Name : getRootPath * @return * @return : String * @C ...

  7. 从头開始写项目Makefile(五):嵌套运行

    [版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 在大一些的项目里面,全部源码不会仅仅放在同一个文件夹,一般各个功 ...

  8. ubuntu16.04 下安装opencv2.4.9

    准备工作,安装环境 sudo apt-get install build-essential cmake libgtk2.0-dev pkg-config python-dev python-nump ...

  9. jquery插件中使用ajax并且获取使用插件的对象

    jquery插件中使用ajax后无法在里面获取this 解决办法是在函数内使用ajax前声明变量 $this=this 然后再ajax中使用$this

  10. mysql忘记root密码且忘了安装目录如何修改root密码

    问题背景 很久之前在本机上安装mysql,也没用过(主要是用Oracle),导致root密码忘记.更严重的是,连自己的安装目录都忘记了. 遇到的问题 1.在任务管理器可以找到mysql的服务已经起来, ...