直接把结构体编码成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. 【2019】问题记录一:后端获取URL参数的值内加号“+”变成空格“ ”

    问题:URL参数中加号“+”变成空格“ ” 一.现象     URL如:http://example.****.com/controller/action?param=rice+cook+panda ...

  2. 关于Android方法数量限制的问题

    限制Android方法数量的原因是: Android应用以DEX文件的形式存储字节码文件,在Dalvik字节码规范里,方法引用索引method referenceindex只有16位,即65536个. ...

  3. linux命令lsattr、chattr、man

    1.man命令,可以查看手册 配置位置/etc/man.conf MANPATH决定手册查询位置 MANSECT决定man查询的顺序 man的查询 linux man的常用用法: man sectio ...

  4. 对ps4 cmask fmask的理解

    这俩都是绑在corlor target上8x8的格子 cmask 做fastclear 这个比较好理解,8x8来表示这个格子是否clear fmask msaa用 provided to suppor ...

  5. 2017.2.9 开涛shiro教程-第十章-会话管理(一)

    原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第十章 会话管理(一) 10.1 会话 shiro提供的会话可以用 ...

  6. bit、位、byte、字节、B、KB、字符与网速

    一.存储单位bit和Byte 1.bit(比特) bit就是位,也叫比特位,是数据存储的最小单位.简写为小写字母“b” 二进制的一位,每个0或1是一个bit 2.Byte(字节) Byte是字节,也有 ...

  7. 白盒测试中如何实现真正意义上并发测试(Java)

    在这个话题开始之前,首先我们来弄清楚为什么要做并发测试? 一般并发测试,是指模拟并发访问,测试多用户并发访问同一个应用.模块.数据时是否产生隐藏的并发问题,如内存泄漏.线程锁.资源争用问题. 站在性能 ...

  8. Android 项目开发实战:聚合数据短信验证码

    聚合数据集成短信验证码官网: https://www.juhe.cn/docs/api/id/54 我根据文档集成了一个例子 效果: 源码下载:http://download.csdn.net/det ...

  9. java导出excel不须要额外jar包

    眼下我知道的在java中导出Excel能够用poi或在jsp的文件头改变输出流. 以下再介绍一种就用java基础包导出的Excel.导出的格式形如: 源代码例如以下: package csvExcel ...

  10. .net 添加web引用和添加服务引用有什么区别?

    添加web引用和添加服务引用有什么区别, Add Service References 和 Add Web References 有啥区别? 参考 http://social.microsoft.co ...