Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
366 lines
15 KiB
366 lines
15 KiB
package json |
|
|
|
import ( |
|
"bytes" |
|
"context" |
|
"encoding/json" |
|
|
|
"github.com/goccy/go-json/internal/encoder" |
|
) |
|
|
|
// Marshaler is the interface implemented by types that |
|
// can marshal themselves into valid JSON. |
|
type Marshaler interface { |
|
MarshalJSON() ([]byte, error) |
|
} |
|
|
|
// MarshalerContext is the interface implemented by types that |
|
// can marshal themselves into valid JSON with context.Context. |
|
type MarshalerContext interface { |
|
MarshalJSON(context.Context) ([]byte, error) |
|
} |
|
|
|
// Unmarshaler is the interface implemented by types |
|
// that can unmarshal a JSON description of themselves. |
|
// The input can be assumed to be a valid encoding of |
|
// a JSON value. UnmarshalJSON must copy the JSON data |
|
// if it wishes to retain the data after returning. |
|
// |
|
// By convention, to approximate the behavior of Unmarshal itself, |
|
// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. |
|
type Unmarshaler interface { |
|
UnmarshalJSON([]byte) error |
|
} |
|
|
|
// UnmarshalerContext is the interface implemented by types |
|
// that can unmarshal with context.Context a JSON description of themselves. |
|
type UnmarshalerContext interface { |
|
UnmarshalJSON(context.Context, []byte) error |
|
} |
|
|
|
// Marshal returns the JSON encoding of v. |
|
// |
|
// Marshal traverses the value v recursively. |
|
// If an encountered value implements the Marshaler interface |
|
// and is not a nil pointer, Marshal calls its MarshalJSON method |
|
// to produce JSON. If no MarshalJSON method is present but the |
|
// value implements encoding.TextMarshaler instead, Marshal calls |
|
// its MarshalText method and encodes the result as a JSON string. |
|
// The nil pointer exception is not strictly necessary |
|
// but mimics a similar, necessary exception in the behavior of |
|
// UnmarshalJSON. |
|
// |
|
// Otherwise, Marshal uses the following type-dependent default encodings: |
|
// |
|
// Boolean values encode as JSON booleans. |
|
// |
|
// Floating point, integer, and Number values encode as JSON numbers. |
|
// |
|
// 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 that had SetEscapeHTML(false) |
|
// called on it. |
|
// |
|
// Array and slice values encode as JSON arrays, except that |
|
// []byte encodes as a base64-encoded string, and a nil slice |
|
// encodes as the null JSON value. |
|
// |
|
// Struct values encode as JSON objects. |
|
// Each exported struct field becomes a member of the object, using the |
|
// field name as the object key, unless the field is omitted for one of the |
|
// reasons given below. |
|
// |
|
// The encoding of each struct field can be customized by the format string |
|
// stored under the "json" key in the struct field's tag. |
|
// The format string gives the name of the field, possibly followed by a |
|
// comma-separated list of options. The name may be empty in order to |
|
// specify options without overriding the default field name. |
|
// |
|
// The "omitempty" option specifies that the field should be omitted |
|
// from the encoding if the field has an empty value, defined as |
|
// false, 0, a nil pointer, a nil interface value, and any empty array, |
|
// slice, map, or string. |
|
// |
|
// As a special case, if the field tag is "-", the field is always omitted. |
|
// Note that a field with name "-" can still be generated using the tag "-,". |
|
// |
|
// Examples of struct field tags and their meanings: |
|
// |
|
// // Field appears in JSON as key "myName". |
|
// Field int `json:"myName"` |
|
// |
|
// // Field appears in JSON as key "myName" and |
|
// // the field is omitted from the object if its value is empty, |
|
// // as defined above. |
|
// Field int `json:"myName,omitempty"` |
|
// |
|
// // Field appears in JSON as key "Field" (the default), but |
|
// // the field is skipped if empty. |
|
// // Note the leading comma. |
|
// Field int `json:",omitempty"` |
|
// |
|
// // Field is ignored by this package. |
|
// Field int `json:"-"` |
|
// |
|
// // Field appears in JSON as key "-". |
|
// Field int `json:"-,"` |
|
// |
|
// The "string" option signals that a field is stored as JSON inside a |
|
// JSON-encoded string. It applies only to fields of string, floating point, |
|
// integer, or boolean types. This extra level of encoding is sometimes used |
|
// when communicating with JavaScript programs: |
|
// |
|
// Int64String int64 `json:",string"` |
|
// |
|
// The key name will be used if it's a non-empty string consisting of |
|
// only Unicode letters, digits, and ASCII punctuation except quotation |
|
// marks, backslash, and comma. |
|
// |
|
// Anonymous struct fields are usually marshaled as if their inner exported fields |
|
// were fields in the outer struct, subject to the usual Go visibility rules amended |
|
// as described in the next paragraph. |
|
// An anonymous struct field with a name given in its JSON tag is treated as |
|
// having that name, rather than being anonymous. |
|
// An anonymous struct field of interface type is treated the same as having |
|
// that type as its name, rather than being anonymous. |
|
// |
|
// The Go visibility rules for struct fields are amended for JSON when |
|
// deciding which field to marshal or unmarshal. If there are |
|
// multiple fields at the same level, and that level is the least |
|
// nested (and would therefore be the nesting level selected by the |
|
// usual Go rules), the following extra rules apply: |
|
// |
|
// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, |
|
// even if there are multiple untagged fields that would otherwise conflict. |
|
// |
|
// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. |
|
// |
|
// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. |
|
// |
|
// Handling of anonymous struct fields is new in Go 1.1. |
|
// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of |
|
// an anonymous struct field in both current and earlier versions, give the field |
|
// a JSON tag of "-". |
|
// |
|
// Map values encode as JSON objects. The map's key type must either be a |
|
// string, an integer type, or implement encoding.TextMarshaler. The map keys |
|
// are sorted and used as JSON object keys by applying the following rules, |
|
// subject to the UTF-8 coercion described for string values above: |
|
// - string keys are used directly |
|
// - encoding.TextMarshalers are marshaled |
|
// - integer keys are converted to strings |
|
// |
|
// Pointer values encode as the value pointed to. |
|
// A nil pointer encodes as the null JSON value. |
|
// |
|
// Interface values encode as the value contained in the interface. |
|
// A nil interface value encodes as the null JSON value. |
|
// |
|
// Channel, complex, and function values cannot be encoded in JSON. |
|
// Attempting to encode such a value causes Marshal to return |
|
// an UnsupportedTypeError. |
|
// |
|
// JSON cannot represent cyclic data structures and Marshal does not |
|
// handle them. Passing cyclic structures to Marshal will result in |
|
// an infinite recursion. |
|
// |
|
func Marshal(v interface{}) ([]byte, error) { |
|
return MarshalWithOption(v) |
|
} |
|
|
|
// MarshalNoEscape returns the JSON encoding of v and doesn't escape v. |
|
func MarshalNoEscape(v interface{}) ([]byte, error) { |
|
return marshalNoEscape(v) |
|
} |
|
|
|
// MarshalContext returns the JSON encoding of v with context.Context and EncodeOption. |
|
func MarshalContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) { |
|
return marshalContext(ctx, v, optFuncs...) |
|
} |
|
|
|
// MarshalWithOption returns the JSON encoding of v with EncodeOption. |
|
func MarshalWithOption(v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) { |
|
return marshal(v, optFuncs...) |
|
} |
|
|
|
// MarshalIndent is like Marshal but applies Indent to format the output. |
|
// Each JSON element in the output will begin on a new line beginning with prefix |
|
// followed by one or more copies of indent according to the indentation nesting. |
|
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { |
|
return MarshalIndentWithOption(v, prefix, indent) |
|
} |
|
|
|
// MarshalIndentWithOption is like Marshal but applies Indent to format the output with EncodeOption. |
|
func MarshalIndentWithOption(v interface{}, prefix, indent string, optFuncs ...EncodeOptionFunc) ([]byte, error) { |
|
return marshalIndent(v, prefix, indent, optFuncs...) |
|
} |
|
|
|
// Unmarshal parses the JSON-encoded data and stores the result |
|
// in the value pointed to by v. If v is nil or not a pointer, |
|
// Unmarshal returns an InvalidUnmarshalError. |
|
// |
|
// Unmarshal uses the inverse of the encodings that |
|
// Marshal uses, allocating maps, slices, and pointers as necessary, |
|
// with the following additional rules: |
|
// |
|
// To unmarshal JSON into a pointer, Unmarshal first handles the case of |
|
// the JSON being the JSON literal null. In that case, Unmarshal sets |
|
// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into |
|
// the value pointed at by the pointer. If the pointer is nil, Unmarshal |
|
// allocates a new value for it to point to. |
|
// |
|
// To unmarshal JSON into a value implementing the Unmarshaler interface, |
|
// Unmarshal calls that value's UnmarshalJSON method, including |
|
// when the input is a JSON null. |
|
// Otherwise, if the value implements encoding.TextUnmarshaler |
|
// and the input is a JSON quoted string, Unmarshal calls that value's |
|
// UnmarshalText method with the unquoted form of the string. |
|
// |
|
// To unmarshal JSON into a struct, Unmarshal matches incoming object |
|
// keys to the keys used by Marshal (either the struct field name or its tag), |
|
// preferring an exact match but also accepting a case-insensitive match. By |
|
// default, object keys which don't have a corresponding struct field are |
|
// ignored (see Decoder.DisallowUnknownFields for an alternative). |
|
// |
|
// To unmarshal JSON into an interface value, |
|
// Unmarshal stores one of these in the interface value: |
|
// |
|
// bool, for JSON booleans |
|
// float64, for JSON numbers |
|
// string, for JSON strings |
|
// []interface{}, for JSON arrays |
|
// map[string]interface{}, for JSON objects |
|
// nil for JSON null |
|
// |
|
// To unmarshal a JSON array into a slice, Unmarshal resets the slice length |
|
// to zero and then appends each element to the slice. |
|
// As a special case, to unmarshal an empty JSON array into a slice, |
|
// Unmarshal replaces the slice with a new empty slice. |
|
// |
|
// To unmarshal a JSON array into a Go array, Unmarshal decodes |
|
// JSON array elements into corresponding Go array elements. |
|
// If the Go array is smaller than the JSON array, |
|
// the additional JSON array elements are discarded. |
|
// If the JSON array is smaller than the Go array, |
|
// the additional Go array elements are set to zero values. |
|
// |
|
// To unmarshal a JSON object into a map, Unmarshal first establishes a map to |
|
// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal |
|
// reuses the existing map, keeping existing entries. Unmarshal then stores |
|
// key-value pairs from the JSON object into the map. The map's key type must |
|
// either be any string type, an integer, implement json.Unmarshaler, or |
|
// implement encoding.TextUnmarshaler. |
|
// |
|
// If a JSON value is not appropriate for a given target type, |
|
// or if a JSON number overflows the target type, Unmarshal |
|
// skips that field and completes the unmarshaling as best it can. |
|
// If no more serious errors are encountered, Unmarshal returns |
|
// an UnmarshalTypeError describing the earliest such error. In any |
|
// case, it's not guaranteed that all the remaining fields following |
|
// the problematic one will be unmarshaled into the target object. |
|
// |
|
// The JSON null value unmarshals into an interface, map, pointer, or slice |
|
// by setting that Go value to nil. Because null is often used in JSON to mean |
|
// ``not present,'' unmarshaling a JSON null into any other Go type has no effect |
|
// on the value and produces no error. |
|
// |
|
// When unmarshaling quoted strings, invalid UTF-8 or |
|
// invalid UTF-16 surrogate pairs are not treated as an error. |
|
// Instead, they are replaced by the Unicode replacement |
|
// character U+FFFD. |
|
// |
|
func Unmarshal(data []byte, v interface{}) error { |
|
return unmarshal(data, v) |
|
} |
|
|
|
// UnmarshalContext parses the JSON-encoded data and stores the result |
|
// in the value pointed to by v. If you implement the UnmarshalerContext interface, |
|
// call it with ctx as an argument. |
|
func UnmarshalContext(ctx context.Context, data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { |
|
return unmarshalContext(ctx, data, v) |
|
} |
|
|
|
func UnmarshalWithOption(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { |
|
return unmarshal(data, v, optFuncs...) |
|
} |
|
|
|
func UnmarshalNoEscape(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { |
|
return unmarshalNoEscape(data, v, optFuncs...) |
|
} |
|
|
|
// A Token holds a value of one of these types: |
|
// |
|
// Delim, for the four JSON delimiters [ ] { } |
|
// bool, for JSON booleans |
|
// float64, for JSON numbers |
|
// Number, for JSON numbers |
|
// string, for JSON string literals |
|
// nil, for JSON null |
|
// |
|
type Token = json.Token |
|
|
|
// A Number represents a JSON number literal. |
|
type Number = json.Number |
|
|
|
// RawMessage is a raw encoded JSON value. |
|
// It implements Marshaler and Unmarshaler and can |
|
// be used to delay JSON decoding or precompute a JSON encoding. |
|
type RawMessage = json.RawMessage |
|
|
|
// A Delim is a JSON array or object delimiter, one of [ ] { or }. |
|
type Delim = json.Delim |
|
|
|
// Compact appends to dst the JSON-encoded src with |
|
// insignificant space characters elided. |
|
func Compact(dst *bytes.Buffer, src []byte) error { |
|
return encoder.Compact(dst, src, false) |
|
} |
|
|
|
// Indent appends to dst an indented form of the JSON-encoded src. |
|
// Each element in a JSON object or array begins on a new, |
|
// indented line beginning with prefix followed by one or more |
|
// copies of indent according to the indentation nesting. |
|
// The data appended to dst does not begin with the prefix nor |
|
// any indentation, to make it easier to embed inside other formatted JSON data. |
|
// Although leading space characters (space, tab, carriage return, newline) |
|
// at the beginning of src are dropped, trailing space characters |
|
// at the end of src are preserved and copied to dst. |
|
// For example, if src has no trailing spaces, neither will dst; |
|
// if src ends in a trailing newline, so will dst. |
|
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { |
|
return encoder.Indent(dst, src, prefix, indent) |
|
} |
|
|
|
// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 |
|
// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 |
|
// so that the JSON will be safe to embed inside HTML <script> tags. |
|
// For historical reasons, web browsers don't honor standard HTML |
|
// escaping within <script> tags, so an alternative JSON encoding must |
|
// be used. |
|
func HTMLEscape(dst *bytes.Buffer, src []byte) { |
|
var v interface{} |
|
dec := NewDecoder(bytes.NewBuffer(src)) |
|
dec.UseNumber() |
|
if err := dec.Decode(&v); err != nil { |
|
return |
|
} |
|
buf, _ := marshal(v) |
|
dst.Write(buf) |
|
} |
|
|
|
// Valid reports whether data is a valid JSON encoding. |
|
func Valid(data []byte) bool { |
|
var v interface{} |
|
decoder := NewDecoder(bytes.NewReader(data)) |
|
err := decoder.Decode(&v) |
|
if err != nil { |
|
return false |
|
} |
|
if !decoder.More() { |
|
return true |
|
} |
|
return decoder.InputOffset() >= int64(len(data)) |
|
}
|
|
|