OLD | NEW |
1 // Copyright 2010 The Go Authors. All rights reserved. | 1 // Copyright 2010 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Package json implements encoding and decoding of JSON objects as defined in | 5 // Package json implements encoding and decoding of JSON objects as defined in |
6 // RFC 4627. | 6 // RFC 4627. |
7 package json | 7 package json |
8 | 8 |
9 import ( | 9 import ( |
10 "bytes" | 10 "bytes" |
11 "encoding/base64" | 11 "encoding/base64" |
12 "os" | 12 "os" |
13 "reflect" | 13 "reflect" |
14 "runtime" | 14 "runtime" |
15 "sort" | 15 "sort" |
16 "strconv" | 16 "strconv" |
17 "strings" | |
18 "unicode" | 17 "unicode" |
19 "utf8" | 18 "utf8" |
20 ) | 19 ) |
21 | 20 |
22 // Marshal returns the JSON encoding of v. | 21 // Marshal returns the JSON encoding of v. |
23 // | 22 // |
24 // Marshal traverses the value v recursively. | 23 // Marshal traverses the value v recursively. |
25 // If an encountered value implements the Marshaler interface, | 24 // If an encountered value implements the Marshaler interface, |
26 // Marshal calls its MarshalJSON method to produce JSON. | 25 // Marshal calls its MarshalJSON method to produce JSON. |
27 // | 26 // |
(...skipping 24 matching lines...) Expand all Loading... |
52 // // Specifies that Field appears in JSON as key "myName" and | 51 // // Specifies that Field appears in JSON as key "myName" and |
53 // // the field is omitted from the object if its value is empty, | 52 // // the field is omitted from the object if its value is empty, |
54 // // as defined above. | 53 // // as defined above. |
55 // Field int `json:"myName,omitempty"` | 54 // Field int `json:"myName,omitempty"` |
56 // | 55 // |
57 // // Field appears in JSON as key "Field" (the default), but | 56 // // Field appears in JSON as key "Field" (the default), but |
58 // // the field is skipped if empty. | 57 // // the field is skipped if empty. |
59 // // Note the leading comma. | 58 // // Note the leading comma. |
60 // Field int `json:",omitempty"` | 59 // Field int `json:",omitempty"` |
61 // | 60 // |
| 61 // The "string" option signals that a field is stored as JSON inside a |
| 62 // JSON-encoded string. This extra level of encoding is sometimes |
| 63 // used when communicating with JavaScript programs: |
| 64 // |
| 65 // Int64String int64 `json:",string"` |
| 66 // |
62 // The key name will be used if it's a non-empty string consisting of | 67 // The key name will be used if it's a non-empty string consisting of |
63 // only Unicode letters, digits, dollar signs, hyphens, and underscores. | 68 // only Unicode letters, digits, dollar signs, hyphens, and underscores. |
64 // | 69 // |
65 // Map values encode as JSON objects. | 70 // Map values encode as JSON objects. |
66 // The map's key type must be string; the object keys are used directly | 71 // The map's key type must be string; the object keys are used directly |
67 // as map keys. | 72 // as map keys. |
68 // | 73 // |
69 // Pointer values encode as the value pointed to. | 74 // Pointer values encode as the value pointed to. |
70 // A nil pointer encodes as the null JSON object. | 75 // A nil pointer encodes as the null JSON object. |
71 // | 76 // |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 return v.Uint() == 0 | 219 return v.Uint() == 0 |
215 case reflect.Float32, reflect.Float64: | 220 case reflect.Float32, reflect.Float64: |
216 return v.Float() == 0 | 221 return v.Float() == 0 |
217 case reflect.Interface, reflect.Ptr: | 222 case reflect.Interface, reflect.Ptr: |
218 return v.IsNil() | 223 return v.IsNil() |
219 } | 224 } |
220 return false | 225 return false |
221 } | 226 } |
222 | 227 |
223 func (e *encodeState) reflectValue(v reflect.Value) { | 228 func (e *encodeState) reflectValue(v reflect.Value) { |
| 229 e.reflectValueQuoted(v, false) |
| 230 } |
| 231 |
| 232 // reflectValueQuoted writes the value in v to the output. |
| 233 // If quoted is true, the serialization is wrapped in a JSON string. |
| 234 func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) { |
224 if !v.IsValid() { | 235 if !v.IsValid() { |
225 e.WriteString("null") | 236 e.WriteString("null") |
226 return | 237 return |
227 } | 238 } |
228 | 239 |
229 if j, ok := v.Interface().(Marshaler); ok { | 240 if j, ok := v.Interface().(Marshaler); ok { |
230 b, err := j.MarshalJSON() | 241 b, err := j.MarshalJSON() |
231 if err == nil { | 242 if err == nil { |
232 // copy JSON into buffer, checking validity. | 243 // copy JSON into buffer, checking validity. |
233 err = Compact(&e.Buffer, b) | 244 err = Compact(&e.Buffer, b) |
234 } | 245 } |
235 if err != nil { | 246 if err != nil { |
236 e.error(&MarshalerError{v.Type(), err}) | 247 e.error(&MarshalerError{v.Type(), err}) |
237 } | 248 } |
238 return | 249 return |
239 } | 250 } |
240 | 251 |
| 252 writeString := (*encodeState).WriteString |
| 253 if quoted { |
| 254 writeString = (*encodeState).string |
| 255 } |
| 256 |
241 switch v.Kind() { | 257 switch v.Kind() { |
242 case reflect.Bool: | 258 case reflect.Bool: |
243 x := v.Bool() | 259 x := v.Bool() |
244 if x { | 260 if x { |
245 » » » e.WriteString("true") | 261 » » » writeString(e, "true") |
246 } else { | 262 } else { |
247 » » » e.WriteString("false") | 263 » » » writeString(e, "false") |
248 } | 264 } |
249 | 265 |
250 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.In
t64: | 266 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.In
t64: |
251 » » e.WriteString(strconv.Itoa64(v.Int())) | 267 » » writeString(e, strconv.Itoa64(v.Int())) |
252 | 268 |
253 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflec
t.Uint64, reflect.Uintptr: | 269 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflec
t.Uint64, reflect.Uintptr: |
254 » » e.WriteString(strconv.Uitoa64(v.Uint())) | 270 » » writeString(e, strconv.Uitoa64(v.Uint())) |
255 | 271 |
256 case reflect.Float32, reflect.Float64: | 272 case reflect.Float32, reflect.Float64: |
257 » » e.WriteString(strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits())
) | 273 » » writeString(e, strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()
)) |
258 | 274 |
259 case reflect.String: | 275 case reflect.String: |
260 » » e.string(v.String()) | 276 » » if quoted { |
| 277 » » » sb, err := Marshal(v.String()) |
| 278 » » » if err != nil { |
| 279 » » » » e.error(err) |
| 280 » » » } |
| 281 » » » e.string(string(sb)) |
| 282 » » } else { |
| 283 » » » e.string(v.String()) |
| 284 » » } |
261 | 285 |
262 case reflect.Struct: | 286 case reflect.Struct: |
263 e.WriteByte('{') | 287 e.WriteByte('{') |
264 t := v.Type() | 288 t := v.Type() |
265 n := v.NumField() | 289 n := v.NumField() |
266 first := true | 290 first := true |
267 for i := 0; i < n; i++ { | 291 for i := 0; i < n; i++ { |
268 f := t.Field(i) | 292 f := t.Field(i) |
269 if f.PkgPath != "" { | 293 if f.PkgPath != "" { |
270 continue | 294 continue |
271 } | 295 } |
272 » » » tag, omitEmpty := f.Name, false | 296 » » » tag, omitEmpty, quoted := f.Name, false, false |
273 if tv := f.Tag.Get("json"); tv != "" { | 297 if tv := f.Tag.Get("json"); tv != "" { |
274 » » » » ss := strings.SplitN(tv, ",", 2) | 298 » » » » name, opts := parseTag(tv) |
275 » » » » if isValidTag(ss[0]) { | 299 » » » » if isValidTag(name) { |
276 » » » » » tag = ss[0] | 300 » » » » » tag = name |
277 } | 301 } |
278 » » » » if len(ss) > 1 { | 302 » » » » omitEmpty = opts.Contains("omitempty") |
279 » » » » » // Currently the only option is omitempt
y, | 303 » » » » quoted = opts.Contains("string") |
280 » » » » » // so parsing is trivial. | |
281 » » » » » omitEmpty = ss[1] == "omitempty" | |
282 » » » » } | |
283 } | 304 } |
284 fieldValue := v.Field(i) | 305 fieldValue := v.Field(i) |
285 if omitEmpty && isEmptyValue(fieldValue) { | 306 if omitEmpty && isEmptyValue(fieldValue) { |
286 continue | 307 continue |
287 } | 308 } |
288 if first { | 309 if first { |
289 first = false | 310 first = false |
290 } else { | 311 } else { |
291 e.WriteByte(',') | 312 e.WriteByte(',') |
292 } | 313 } |
293 e.string(tag) | 314 e.string(tag) |
294 e.WriteByte(':') | 315 e.WriteByte(':') |
295 » » » e.reflectValue(fieldValue) | 316 » » » e.reflectValueQuoted(fieldValue, quoted) |
296 } | 317 } |
297 e.WriteByte('}') | 318 e.WriteByte('}') |
298 | 319 |
299 case reflect.Map: | 320 case reflect.Map: |
300 if v.Type().Key().Kind() != reflect.String { | 321 if v.Type().Key().Kind() != reflect.String { |
301 e.error(&UnsupportedTypeError{v.Type()}) | 322 e.error(&UnsupportedTypeError{v.Type()}) |
302 } | 323 } |
303 if v.IsNil() { | 324 if v.IsNil() { |
304 e.WriteString("null") | 325 e.WriteString("null") |
305 break | 326 break |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 | 394 |
374 // stringValues is a slice of reflect.Value holding *reflect.StringValue. | 395 // stringValues is a slice of reflect.Value holding *reflect.StringValue. |
375 // It implements the methods to sort by string. | 396 // It implements the methods to sort by string. |
376 type stringValues []reflect.Value | 397 type stringValues []reflect.Value |
377 | 398 |
378 func (sv stringValues) Len() int { return len(sv) } | 399 func (sv stringValues) Len() int { return len(sv) } |
379 func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } | 400 func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } |
380 func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) } | 401 func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) } |
381 func (sv stringValues) get(i int) string { return sv[i].String() } | 402 func (sv stringValues) get(i int) string { return sv[i].String() } |
382 | 403 |
383 func (e *encodeState) string(s string) { | 404 func (e *encodeState) string(s string) (int, os.Error) { |
| 405 » len0 := e.Len() |
384 e.WriteByte('"') | 406 e.WriteByte('"') |
385 start := 0 | 407 start := 0 |
386 for i := 0; i < len(s); { | 408 for i := 0; i < len(s); { |
387 if b := s[i]; b < utf8.RuneSelf { | 409 if b := s[i]; b < utf8.RuneSelf { |
388 if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b !
= '>' { | 410 if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b !
= '>' { |
389 i++ | 411 i++ |
390 continue | 412 continue |
391 } | 413 } |
392 if start < i { | 414 if start < i { |
393 e.WriteString(s[start:i]) | 415 e.WriteString(s[start:i]) |
(...skipping 24 matching lines...) Expand all Loading... |
418 c, size := utf8.DecodeRuneInString(s[i:]) | 440 c, size := utf8.DecodeRuneInString(s[i:]) |
419 if c == utf8.RuneError && size == 1 { | 441 if c == utf8.RuneError && size == 1 { |
420 e.error(&InvalidUTF8Error{s}) | 442 e.error(&InvalidUTF8Error{s}) |
421 } | 443 } |
422 i += size | 444 i += size |
423 } | 445 } |
424 if start < len(s) { | 446 if start < len(s) { |
425 e.WriteString(s[start:]) | 447 e.WriteString(s[start:]) |
426 } | 448 } |
427 e.WriteByte('"') | 449 e.WriteByte('"') |
| 450 return e.Len() - len0, nil |
428 } | 451 } |
OLD | NEW |