> For the complete documentation index, see [llms.txt](https://minilabmemo.gitbook.io/golang-memo/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://minilabmemo.gitbook.io/golang-memo/advance-application/ge-shi/json.md).

# json

### json tag

* struct tag : field要大寫開頭，tag各有其功用

<pre class="language-diff"><code class="lang-diff">+// Field appears in JSON as key "myName" 
+ and the field is omitted from the object if its value is empty,
NickName string `json:"nick_name,omitempty"` 
+//Field appears in JSON as key "Field" (大寫), but the field is skipped if empty.
Address string `json:",omitempty"` 
<strong>+// Field is ignored by this package.
</strong>A string `json:"-"` 
+// Field appears in JSON as key "-".
B string `json:"-,"` 
+//將輸出轉為string
AgeString int64 `json:"AgeString,string"` 
</code></pre>

### json Marshel

* 返回 v 的 JSON 编码
* supported type See \[[json/encode](https://github.com/golang/go/blob/master/src/encoding/json/encode.go)]
* 將struct 轉成 json string
* Marshel如果字串含有HTML特殊字元會被轉換，如果不想要被轉換需要自己將EscapeHTML設為false

<details>

<summary>[線上範例](<a href="https://go.dev/play/p/GL8zgnPMKpv">https://go.dev/play/p/GL8zgnPMKpv</a>)</summary>

```go
package main

import (
"bytes"
"encoding/json"
"fmt"
)

//field要大寫開頭，tag各有其功用
type UserDetail struct {
Name string `json:"name"`
NickName string `json:"nick_name,omitempty"` // Field appears in JSON as key "myName" and the field is omitted from the object if its value is empty,
Address string `json:",omitempty"` //Field appears in JSON as key "Field" (大寫), but the field is skipped if empty.
A string `json:"-"` // Field is ignored by this package.
B string `json:"-,"` // Field appears in JSON as key "-".
AgeString int64 `json:"AgeString,string"` //將輸出轉為string
Age int64 `json:"Age"`
}
type User struct {
Name string `json:"name"`
}

func main() {
user1 := UserDetail{Name: "123", NickName: "123", Address: "123", A: "A", B: "B", AgeString: 123, Age: 12}
jsonMarshal(user1) //-> json str: {"name":"123","my_name":"123","MyName2":"123","-":"B","int64string":"123","int64":123}

value := make(chan int) //unsupportedTypeEncoder #ref1
jsonMarshal(value) //->Marshal err: json: unsupported type: chan int json str:

user2 := User{Name: "<h1>123</h1>"}
jsonMarshal(user2) //->json str: json str: {"name":"\u003ch1\u003e123\u003c/h1\u003e"}
JsonMarshalEscapeHTMLfalse(user2) ->json str: {"name":"<h1>123</h1>"}
}

//struct to json string
func jsonMarshal(u interface{}) {
ub, err := json.Marshal(u)
if err != nil {
fmt.Println("Marshal err:", err)
}
fmt.Println("json str:", string(ub))
}

func JsonMarshalEscapeHTMLfalse(u interface{}) {
ub, err := JsonEscapeHTMLfalse(u)
if err != nil {
fmt.Println("JsonEscapeHTMLfalse err:", err)
}
fmt.Println("json str:", string(ub))
}

func JsonEscapeHTMLfalse(t interface{}) ([]byte, error) {
buffer := &bytes.Buffer{}
encoder := json.NewEncoder(buffer)
encoder.SetEscapeHTML(false)
err := encoder.Encode(t)
return buffer.Bytes(), err
}
o
```

</details>

### json.Unmarshal

* 將json string轉為struct，需了解傳送過來json的結構, 利用type struct 去定義好之後再進行解析
* 利用 \`map\[string]interface{}\`轉換，但想要取資料解析後比較麻煩，不像是知道結構方便
* 可以用map取第一層，下一層需reflect，下下層也是...或是利用斷言
* 僅僅需要將某字串格式化可用
* 小地方注意：在进行反序列化操作时：第二个参数应该i传地址

```diff
+json.Unmarshal([]byte(data), &ns)
-json.Unmarshal([]byte(data), ns)  出錯json: Unmarshal(non-pointer，也會出現毛毛蟲

-json: Unmarshal(non-pointer message.Message)
-反序列化出错出现错误的原因是：在进行反序列化操作时：第二个参数应该i传地址
```

<details>

<summary>(ex1):<a href="https://go.dev/play/p/kFzxUGvoDNJ">https://go.dev/play/p/kFzxUGvoDNJ</a></summary>

```go
package main

import (
"encoding/json"
"fmt"
)

type User struct {
Name string `json:"name"`
Age int64 `json:"Age"`
Detail Detail `json:"detail"`
}

type Detail struct {
Address string `json:"address"`
}

func main() {
s := `{"name": "123",
"age": 23,
"detail": {
"Address": "abd"
}
}`

var d2 User //定義已知結構
if err := json.Unmarshal([]byte(s), &d2); err != nil {
fmt.Println(err)
}
fmt.Println(d2)
fmt.Println(d2.Detail.Address) //可以很輕鬆拿到內容

}
```

</details>

#### json.Compact

如果json string是beautify JSON String，json.Compact可以做壓縮。

<details>

<summary>範例</summary>

```go
/func main() {
s := `{"name": "123",
"age": 23,
"detail": {
"Address": "abd"
}
}` //json字串是 beautify JSON String

minfy := compactJSON([]byte(s))
fmt.Println(string(minfy))

}

//json.Compact
func compactJSON(js []byte) []byte {
buf := new(bytes.Buffer)
if err := json.Compact(buf, js); err != nil {
fmt.Println(err)
return nil
}
return buf.Bytes()
}
```

</details>

#### 轉換練習

* JSON String to String, string to JSON String
* <https://go.dev/play/p/04-7p4anrQk>
* beautify JSON String to String, string to JSON String
* <https://go.dev/play/p/ySUIE73ls23><br>

#### reference

| 來源                                                                                                                                                                                                                           | 筆記                                                                                      |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| <p></p><p><a href="https://stackoverflow.com/questions/33903552/what-input-will-cause-golangs-json-marshal-to-return-an-error">What input will cause golang's json.Marshal to return an error?</a><br></p>                   | <p>json.Marshal types</p><p>e.g. func or chan refuse to serialize</p>                   |
| [\[Golang JSON 處理\]](https://blog.dexiang.me/zh-tw/technologies/golang-json/\))                                                                                                                                              |                                                                                         |
| <p></p><p><a href="https://www.icodebang.com/article/252820">\[Golang中的读写数据（下）--JSON数据的编码与解码（筑基三层）]</a></p><p></p>                                                                                                           | <p>struct tag 還可以有以下功能</p><p>printJson(key string, value interface{})</p>               |
| [Ｇolang — json Unmarshal 轉換碰上type interface {} does not support indexing](https://sam66.medium.com/%EF%BD%87olang-json-unmarshal-%E8%BD%89%E6%8F%9B%E7%A2%B0%E4%B8%8Atype-interface-does-not-support-indexing-48e6b03aa7c1)] |                                                                                         |
| \[[还在用 map\[string\]interface{} 处理 JSON？告诉你一个更高效的方法——jsonvalue](https://segmentfault.com/a/1190000023564781)                                                                                                                 |                                                                                         |
| [标准库 encoding/json 的进化之路](https://studygolang.com/articles/25100)                                                                                                                                                            | 各个 Go 版本中，标准库 encoding/json 的性能表现 在做出使用第三方序列化库替换标准库的决定前，最好先测试下 json 序列化和反序列化是否是应用的性能瓶颈点 |
| <p><a href="https://liqiang.io/post/deep-copy-structs-in-go">Go 语言中的深拷贝</a><br>copier 和 json 的性能<br></p>                                                                                                                     | TBD: 編按：雖然本文章說json性能較差 但go1.17實測jaon比較好？why?                                            |
|                                                                                                                                                                                                                              |                                                                                         |
