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
|
package json
import (
"bytes"
"encoding/json"
"fmt"
"io"
)
// DiscardUnknownField discards unknown fields from a decoder body.
// This function is useful while deserializing a JSON body with additional
// unknown information that should be discarded.
func DiscardUnknownField(decoder *json.Decoder) error {
// This deliberately does not share logic with CollectUnknownField, even
// though it could, because if we were to delegate to that then we'd incur
// extra allocations and general memory usage.
v, err := decoder.Token()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if _, ok := v.(json.Delim); ok {
for decoder.More() {
err = DiscardUnknownField(decoder)
}
endToken, err := decoder.Token()
if err != nil {
return err
}
if _, ok := endToken.(json.Delim); !ok {
return fmt.Errorf("invalid JSON : expected json delimiter, found %T %v",
endToken, endToken)
}
}
return nil
}
// CollectUnknownField grabs the contents of unknown fields from the decoder body
// and returns them as a byte slice. This is useful for skipping unknown fields without
// completely discarding them.
func CollectUnknownField(decoder *json.Decoder) ([]byte, error) {
result, err := collectUnknownField(decoder)
if err != nil {
return nil, err
}
buff := bytes.NewBuffer(nil)
encoder := json.NewEncoder(buff)
if err := encoder.Encode(result); err != nil {
return nil, err
}
return buff.Bytes(), nil
}
func collectUnknownField(decoder *json.Decoder) (interface{}, error) {
// Grab the initial value. This could either be a concrete value like a string or a a
// delimiter.
token, err := decoder.Token()
if err == io.EOF {
return nil, nil
}
if err != nil {
return nil, err
}
// If it's an array or object, we'll need to recurse.
delim, ok := token.(json.Delim)
if ok {
var result interface{}
if delim == '{' {
result, err = collectUnknownObject(decoder)
if err != nil {
return nil, err
}
} else {
result, err = collectUnknownArray(decoder)
if err != nil {
return nil, err
}
}
// Discard the closing token. decoder.Token handles checking for matching delimiters
if _, err := decoder.Token(); err != nil {
return nil, err
}
return result, nil
}
return token, nil
}
func collectUnknownArray(decoder *json.Decoder) ([]interface{}, error) {
// We need to create an empty array here instead of a nil array, since by getting
// into this function at all we necessarily have seen a non-nil list.
array := []interface{}{}
for decoder.More() {
value, err := collectUnknownField(decoder)
if err != nil {
return nil, err
}
array = append(array, value)
}
return array, nil
}
func collectUnknownObject(decoder *json.Decoder) (map[string]interface{}, error) {
object := make(map[string]interface{})
for decoder.More() {
key, err := collectUnknownField(decoder)
if err != nil {
return nil, err
}
// Keys have to be strings, which is particularly important as the encoder
// won't except a map with interface{} keys
stringKey, ok := key.(string)
if !ok {
return nil, fmt.Errorf("expected string key, found %T", key)
}
value, err := collectUnknownField(decoder)
if err != nil {
return nil, err
}
object[stringKey] = value
}
return object, nil
}
|