-
Notifications
You must be signed in to change notification settings - Fork 0
/
json.go
239 lines (215 loc) · 7.71 KB
/
json.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// author : ysoftman
// encoding : utf-8
// title : json 테스트
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"strconv"
"strings"
)
const strJSON = `
{
"name":"ysoftman",
"age":20,
"history" : {"date":"20141010", "action":"dosomething"},
"source" : "<script>hello world</script>",
"array1" : [1,2,3]
}
`
// JSONDataInner 데이터 타입
type JSONDataInner struct {
Date string
Action string
}
type ExtraStruct struct {
val int
}
// JSONData 데이터 타입
type JSONData struct {
//Name string // json 키값과 같은 이름의 변수를 선언하던가
UserName string `json:"name"` // json key tag 를 명시하던가, marshal시 name 으로 필드명 사용
Age int
History JSONDataInner
Source string `json:"source"`
Extra1 int `json:"zzz,omitempty"` // 값이 비워져 있으면 marshal에서 제외
Extra2 *ExtraStruct `json:",omitempty"` // struct 에 omitempty 를 적용하려면 포인터여야 한다.
Extra3 string `json:"-"` // "-" 로 명시하면 marshal 수행시 무시(제외)된다.
JSONString string `json:"jsonstring"`
Array1 []int `json:"array1"`
Array2 []int `json:"array2"`
Array3 []struct {
a int
b string
} `json:"array3"`
Array4 []ExtraStruct `json:"array4"`
}
// JSONFile : AutoGenerated by https://mholt.github.io/json-to-go
type JSONFile struct {
Key1 string `json:"key1"`
Key2 string `json:"key2"`
Key3 string `json:"key3"`
}
func main() {
fmt.Println("json test...")
marshalJSON()
unmarshalJSON()
unmarshalJSONwithMapInterface()
decodeJSON()
unmarshalJSONFile()
encodeJSON()
HasAIsAJSON()
}
func marshalJSON() {
// bool 형 json 만들기
jsonBool, _ := json.Marshal(true)
fmt.Println("json.Marshal(true) = ", string(jsonBool))
// int 형 json 만들기
jsonInt, _ := json.Marshal(123)
fmt.Println("json.Marshal(123) = ", string(jsonInt))
// string 형 json 만들기
jsonString, _ := json.Marshal("<script>ysoftman</script>")
fmt.Println(`json.Marshal("<script>ysoftman</script>") = `, string(jsonString))
// 배열 json 만들기
array := []string{"red", "green", "blue"}
jsonArray, _ := json.Marshal(array)
fmt.Println("json.Marshal(array) = ", string(jsonArray))
// 맵 json 만들기
obj := map[string]string{"name1": "ysoftman", "name2": "hong gil-dong"}
jsonObj, _ := json.Marshal(obj)
fmt.Println("json.Marshal(obj) = ", string(jsonObj))
// struct json 만들기
jd := &JSONData{}
// jd.Extra2 = &ExtraStruct{val: 1} // Extra2 는 omitempty 로 설정되어 값 설정이 없으면 빠진다.
jsonData, _ := json.Marshal(jd)
fmt.Println("json.Marshal(jd)", string(jsonData))
}
func unmarshalJSON() {
fmt.Println("\nstrJSON", strJSON)
// HTMLEscape (json 데이터를 HTML <scritp>내에서 사용할때 사용)
dst := new(bytes.Buffer)
json.HTMLEscape(dst, []byte(strJSON))
fmt.Println(`json.HTMLEscape(dst, []byte(strJSON)) = `, dst.String())
// json 파싱
jd := &JSONData{}
jd.JSONString = strJSON
json.Unmarshal([]byte(strJSON), &jd)
fmt.Println("json.Unmarshal jd = ", jd)
fmt.Println("json.Unmarshal jd.UserName = ", jd.UserName)
fmt.Println("json.Unmarshal jd.Age = ", jd.Age)
fmt.Println("json.Unmarshal jd.History.Date = ", jd.History.Date)
fmt.Println("json.Unmarshal jd.History.Action = ", jd.History.Action)
// Array2 가 없어 빈값을 표현할때 기본 "arrary2" : null 로 된다.
// "array2" : [] 와 같이 빈 array 를 표현하려면 다음과 같이 설정한다.
jd.Array2 = make([]int, 0)
// struct 를 "array3" : [] 로 표현하려면 다음과 같이 설정한다.
jd.Array3 = []struct {
a int
b string
}{}
// 이미 타입이 있는 struct 를 "array4" : [] 로 표현하려면 다음과 같이 설정한다.
jd.Array4 = []ExtraStruct{}
bytesbuffer := new(bytes.Buffer)
encoder := json.NewEncoder(bytesbuffer)
// html escape 없이 인코딩
encoder.SetEscapeHTML(false)
encoder.SetIndent("", " ")
encoder.Encode(jd)
fmt.Println(`encoder.SetEscapeHTML(false) = `, bytesbuffer.String())
// jsonstring " \n 등에 escape 처리된다.(JSONString 필드 값은 스트링이기때문에 json 내에서 escape 되어야 한다.)
aaa := bytesbuffer.String()
fmt.Println(aaa)
//////////
// escape 제거를 위한 잘못 된 시도들 이렇게 하면 안된다.
// ss, err := strconv.Unquote("\"ysoftman\"")
// ' " 등의 quotation 만 제거 할 수있고, \n 등이 들어가면 invalid syntax 에러
ss, err := strconv.Unquote(aaa)
if err != nil {
fmt.Println("error", err)
}
// replace 로 \n \ 를 제거할 수 있지만 그렇게 되면 json 포맷이 아니게 된다.
// 출력 결과를 ehco ' ' | mjson 으로 확인하면 에러가 발생
// 따라서 위의 escape 된 aaa 를 사용해야 된다.
ss = strings.Replace(aaa, "\\n", "", -1)
ss = strings.Replace(ss, "\\", "", -1)
fmt.Println(`encoder.SetEscapeHTML(false) - strconv.Unquote = `, ss)
//////////
}
func unmarshalJSONwithMapInterface() {
// json 내용을 모를 경우 map[string]interface{} 구조로 unmarshal 할 수 있다.
var mi map[string]interface{}
json.Unmarshal([]byte(strJSON), &mi)
fmt.Println("mi:", mi)
fmt.Println("mi.name = ", mi["name"])
fmt.Println("mi.age = ", mi["age"])
fmt.Println("mi.source = ", mi["source"])
miArr1 := mi["array1"].([]interface{})
fmt.Println("mi.array1[0] = ", miArr1[0])
fmt.Println("mi.array1[1] = ", miArr1[1])
fmt.Println("mi.array1[2] = ", miArr1[2])
// json object 필드는 map[string]interface{} 중첩된 형태로 볼 수 있다.
miHistory := mi["history"].(map[string]interface{})
fmt.Println("mi.history.date:", miHistory["date"])
fmt.Println("mi.history.action:", miHistory["action"])
}
func decodeJSON() {
jd := &JSONData{}
// unmarshal 대신 decode 함수 사용
r := bytes.NewReader([]byte(strJSON))
if err := json.NewDecoder(r).Decode(jd); err != nil {
panic(err)
}
fmt.Println("jd:", jd)
fmt.Println("jd.UserName = ", jd.UserName)
fmt.Println("jd.Age = ", jd.Age)
fmt.Println("jd.Source = ", jd.Source)
fmt.Println("jd.array1 = ", jd.Array1)
fmt.Println("jd.history = ", jd.History)
}
func unmarshalJSONFile() {
// json file 로드
file, err := ioutil.ReadFile("./json_data.json")
if err != nil {
log.Fatal("can't read file ...", err.Error())
}
var jSONfile JSONFile
json.Unmarshal(file, &jSONfile)
fmt.Println("json.Unmarshal jSONfile = ", jSONfile)
fmt.Println("json.Unmarshal jSONfile.Key1 = ", jSONfile.Key1)
fmt.Println("json.Unmarshal jSONfile.Key2 = ", jSONfile.Key2)
fmt.Println("json.Unmarshal jSONfile.Key3 = ", jSONfile.Key3)
}
func encodeJSON() {
// Marshal 은 기본적으로 특수문자들이 유니코드 escape 으로 인코딩된다.
// json/encoding.go Marshal() 주석 중 발췌
// String values encode as JSON strings coerced to valid UTF-8,
// replacing invalid bytes with the Unicode replacement rune.
// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
// to keep some browsers from misinterpreting JSON output as HTML.
// Ampersand "&" is also escaped to "\u0026" for the same reason.
// This escaping can be disabled using an Encoder with DisableHTMLEscaping.
// <, >, & ====> \u003c, \u003e, \u0026
// Marshal 대신 encoder 를 사용하여 escape 없이 인코딩할 수 있다.
bytesbuffer1 := new(bytes.Buffer)
encoder := json.NewEncoder(bytesbuffer1)
// html escape 없이 인코딩
encoder.SetEscapeHTML(false)
encoder.SetIndent("", " ")
encoder.Encode("<script>ysoftman</script>")
fmt.Println("jsonString = ", bytesbuffer1.String())
// struct -> json
bytesbuffer2 := new(bytes.Buffer)
encoder2 := json.NewEncoder(bytesbuffer2)
aaa := struct {
Str string `json:"str"`
Num int `json:"num"`
}{
Str: " lemon",
Num: 123,
}
encoder2.Encode(aaa)
fmt.Println("jsonString = ", bytesbuffer2.String())
}