Documentation
¶
Overview ¶
Package json deals with JSON documents.
This library provides tools to work with raw JSON data, with no attempt to convert it to native go types until the very last moment.
This allows to abide strictly to the JSON standards. In particular, it supports JSON-specifics which are not well handled by the standard library, such as:
- null
- values with a zero value in go (e.g. 0, "", false)
- very large or very high-precision numbers that overflow go native types (e.g. int64, float64)
Main memory usage ¶
The library design is primarily focused on keeping a low memory profile, in terms of space as well as in terms of allocations:
- few things are pointers or require allocations
- most data structures that need a dynamic allocation may be recycled using pools, thus amortizing allocations
- JSON values are isolated in a highly packed in-memory store
- object keys are interned
- lazy JSON value resolution
Immutability ¶
Another design goal of this package is immutability: all provided objects Document, light.Node, [token.Token], values.Value etc are all immutable, and designed to be cheap to clone instead.
Mutating or constructing a JSON Document programmatically requires a Builder to carry out a series of fluent building methods. This produces a modified copy-on-write clone of the original Document.
Extensibility ¶
There are tons of use-cases out there to play with.
Specific modules may be added to extend or improve the default implementations of lexers.Lexer, writers.Writer and stores.Store.
As independent modules, they may bring with them their own set of dependencies without altering the dependencies of the parent module.
The default implementations provided do not bring extra external dependencies.
Index ¶
- Constants
- Variables
- func RedeemBuilder(b *Builder)
- func RedeemDocument(d *Document)
- type Builder
- func (b *Builder) AppendElem(value Document) *Builder
- func (b *Builder) AppendElems(values ...Document) *Builder
- func (b *Builder) AppendKey(key string, value Document) *Builder
- func (b *Builder) Array() *Builder
- func (b *Builder) AtPointer(p Pointer, value Document) *Builder
- func (b *Builder) AtPointerMerge(p Pointer, value Document) *Builder
- func (b *Builder) BoolValue(value bool) *Builder
- func (b Builder) Document() Document
- func (b Builder) Err() error
- func (b *Builder) From(d Document) *Builder
- func (b *Builder) MakeBool(value bool) Document
- func (b *Builder) MakeNull() Document
- func (b *Builder) MakeNumber(value any) Document
- func (b *Builder) MakeString(value string) Document
- func (b *Builder) Null() *Builder
- func (b *Builder) NumberValue(value types.Number) *Builder
- func (b *Builder) NumericalValue(value any) *Builder
- func (b *Builder) Object() *Builder
- func (b Builder) Ok() bool
- func (b *Builder) Reset()
- func (b *Builder) SetErr(err error)
- func (b Builder) Store() stores.Store
- func (b *Builder) StringValue(value string) *Builder
- func (b *Builder) WithRoot(root light.Node) *Builder
- func (b *Builder) WithStore(s stores.Store) *Builder
- type Collection
- func (c *Collection) Append(docs ...Document)
- func (c Collection) AppendText(b []byte) ([]byte, error)
- func (c *Collection) DecodeAppend(r io.Reader) error
- func (c *Collection) Document(index int) Document
- func (c *Collection) Documents() iter.Seq[Document]
- func (c Collection) Encode(w io.Writer) error
- func (c Collection) Len() int
- func (o Collection) LexerFactory() func([]byte) (lexers.Lexer, func())
- func (o Collection) LexerFromReaderFactory() func(io.Reader) (lexers.Lexer, func())
- func (c Collection) MarshalJSON() ([]byte, error)
- func (c *Collection) Reset()
- func (c Collection) Store() stores.Store
- func (o Collection) WriterToWriterFactory() func(io.Writer) (writers.StoreWriter, func())
- type Context
- type DecodeError
- type Document
- func (d Document) AppendText(b []byte) ([]byte, error)
- func (d Document) AtKey(k string) (Document, bool)
- func (d Document) Context() Context
- func (d *Document) Decode(r io.Reader) error
- func (d Document) Elem(i int) (Document, bool)
- func (d Document) Elems() iter.Seq[Document]
- func (d Document) Encode(w io.Writer) error
- func (d Document) GetPointer(p Pointer) (Document, error)
- func (d Document) IsEmpty() bool
- func (d Document) JSONLookup(pointer string) (any, error)
- func (d Document) KeyIndex(k string) (int, bool)
- func (d Document) Kind() nodes.Kind
- func (d Document) Len() int
- func (o Document) LexerFactory() func([]byte) (lexers.Lexer, func())
- func (o Document) LexerFromReaderFactory() func(io.Reader) (lexers.Lexer, func())
- func (d Document) MarshalJSON() ([]byte, error)
- func (d *Document) Node() *light.Node
- func (d Document) Pairs() iter.Seq2[string, Document]
- func (d Document) Store() stores.Store
- func (d Document) String() string
- func (d *Document) UnmarshalJSON(data []byte) error
- func (d Document) Value() (values.Value, bool)
- func (o Document) WriterToWriterFactory() func(io.Writer) (writers.StoreWriter, func())
- type DocumentFactory
- func (f DocumentFactory) Clone(d Document) Document
- func (f DocumentFactory) Empty() Document
- func (o DocumentFactory) LexerFactory() func([]byte) (lexers.Lexer, func())
- func (o DocumentFactory) LexerFromReaderFactory() func(io.Reader) (lexers.Lexer, func())
- func (o DocumentFactory) WriterToWriterFactory() func(io.Writer) (writers.StoreWriter, func())
- type Option
- type Pointer
- type VerbatimDocument
Constants ¶
const ( // ErrPointer is an error raised by a JSON pointer. ErrPointer pointerError = "JSON pointer error" // ErrPointerNotFound is raised when a JSON pointer cannot be resolved against a document. ErrPointerNotFound pointerError = "JSON pointer not found" // ErrInvalidStart states that a JSON pointer must start with a separator ("/"), or be the empty JSON pointer. ErrInvalidStart pointerError = `JSON pointer must be empty or start with a /"` )
Variables ¶
var EmptyDocument = Make()
EmptyDocument is the JSON document of the null type.
It has no stores.Store attached to it.
var EmptyPointer = Pointer([]stringOrInt{})
EmptyPointer represents the empty JSON pointer, which matches a whole document.
Functions ¶
func RedeemBuilder ¶
func RedeemBuilder(b *Builder)
func RedeemDocument ¶
func RedeemDocument(d *Document)
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder builds or transforms JSON Document s programmatically.
You may either use it directly, starting from the EmptyDocument or clone from an existing Document using Builder.From.
Since a Document is immutable, the Builder always produces a shallow clone of the original Document.
The Builder exposes fluent building methods which may be chained to construct a JSON document.
You should always check the final error state, since the building ceases to be effective as soon as an error is encountered.
func BorrowBuilder ¶
func BorrowBuilder() *Builder
func NewBuilder ¶
func (*Builder) AppendElem ¶
AppendElem appends a new element to an array.
func (*Builder) AppendElems ¶
AppendElems appends new elements to an array.
func (*Builder) AtPointer ¶
AtPointer replaces a value in a Document at Pointer.
No replacement is made if the Pointer is not found.
func (*Builder) AtPointerMerge ¶
func (Builder) Document ¶
Document returns the Document produced by the Builder.
If a build error has occurred, it returns the EmptyDocument.
func (*Builder) MakeBool ¶
MakeBool is a shorthand for NewBuilder(b.Store()).BoolValue(value).Document().
func (*Builder) MakeNumber ¶
MakeNumber is a shorthand for NewBuilder(b.Store()).NumericalValue(value).Document().
func (*Builder) MakeString ¶
MakeString is a shorthand for NewBuilder(b.Store()).StringValue(value).Document().
func (*Builder) NumberValue ¶
NumberValue builds a scalar JSON number value.
func (*Builder) NumericalValue ¶
NumericalValue builds a scalar JSON number value from any go numerical type, including types from math/big.
func (*Builder) StringValue ¶
StringValue builds a scalar JSON string
type Collection ¶
type Collection struct {
// contains filtered or unexported fields
}
Collection is a collection of Document s, that share the same options.
It can serve as a factory to produce Document s using Collection.DecodeAppend.
It marshals as an array of [Document]s.
func NewCollection ¶
func NewCollection(opts ...Option) *Collection
NewCollection builds a new empty Collection of Document s.
func (*Collection) Append ¶
func (c *Collection) Append(docs ...Document)
Append a Document to the Collection.
If the Collection is empty, the options will be taken from the first Document appended.
Limitations ¶
- Document s that are based on a different stores.Store won't be added and will be skipped.
func (Collection) AppendText ¶
func (c Collection) AppendText(b []byte) ([]byte, error)
AppendText appends the JSON bytes to the provided buffer and returns the resulting slice.
func (*Collection) DecodeAppend ¶
func (c *Collection) DecodeAppend(r io.Reader) error
DecodeAppend decodes a Document from the provided reader and appends it to the Collection.
func (*Collection) Document ¶
func (c *Collection) Document(index int) Document
Document yields the Document at the index position in the Collection.
It panics if index >= Collection.Len.
func (*Collection) Documents ¶
func (c *Collection) Documents() iter.Seq[Document]
Documents iterates over the Document s in the Collection.
func (Collection) Encode ¶
func (c Collection) Encode(w io.Writer) error
Encode a collection of Document s as a stream of JSON bytes.
func (Collection) Len ¶
func (c Collection) Len() int
Len returns the number of Document s in the collection.
func (Collection) LexerFactory ¶
func (Collection) LexerFromReaderFactory ¶
func (Collection) MarshalJSON ¶
func (c Collection) MarshalJSON() ([]byte, error)
MarshalJSON marshals the Collection as an array of JSON documents.
func (*Collection) Reset ¶
func (c *Collection) Reset()
Reset the collection, so it may be recycled.
func (Collection) Store ¶
func (c Collection) Store() stores.Store
Store returns the underlying stores.Store where JSON values are kept.
func (Collection) WriterToWriterFactory ¶
func (o Collection) WriterToWriterFactory() func(io.Writer) (writers.StoreWriter, func())
type DecodeError ¶
type DecodeError struct {
ErrContext *codes.ErrContext
Path light.Path
}
DecodeError contains details about a JSON decode error.
func (DecodeError) AsError ¶
func (d DecodeError) AsError() error
func (DecodeError) Error ¶
func (d DecodeError) Error() string
type Document ¶
type Document struct {
// contains filtered or unexported fields
}
Document represents a JSON document as a hierarchy of JSON data nodes.
A Document knows how to marshal or unmarshal bytes or decode/encode with streams.
A Document is immutable: it may be unmarshaled from JSON, from [Dynamic JSON] or built programmatically using the Builder.
Accessing nodes ¶
Document.AtKey retrieves an individual keys in an object. Document.Elem does the same for an element in an array.
Iterators ¶
The hierarchy of nodes defined by a Document may be explored using iterators like Document.Pairs and Document.Elems.
Iterators maintain the original order in which object keys and array elements have been provided.
Exploring a document ¶
JSON pointers are supported within a Document using Document.GetPointer.
An implementation of JSONPath is provided in github.com/fredbi/core/json/documents.jsonpath to resolve JSONPath expressions as a Document iterator.
Working with values ¶
TODO(fred): documentation
Dynamic JSON ¶
We call "dynamic JSON" (sometimes referred to as "untyped") refers to the go structures made up of "map[string]any" and "[]any" that you typically get when the go standard library unmarshals JSON into an "any" type (aka "interface{}").
A Document may unmarshal such a data structure or may be converted into one.
In that case, due to the implementation of go maps, the order of keys in objects cannot be maintained.
Related projects ¶
This package only deals with pure JSON, not schemas.
Package github.com/fredbi/core/jsonschma brings the additional logic required to deal with JSON schemas.
Package github.com/fredbi/core/spec brings the additional logic required to deal with OpenAPI documents.
func BorrowDocument ¶
func BorrowDocument() *Document
func (Document) AppendText ¶
AppendText appends the JSON bytes to the provided buffer and returns the resulting slice.
func (Document) AtKey ¶
AtKey returns the value held under a key in an object, or false if not found.
Key lookup is constant-time (map index).
func (Document) Context ¶
Context returns the decode context of the document root, i.e a bytes count offset.
func (*Document) Decode ¶
Decode builds a Document from a stream of JSON bytes.
TODO: rename DecodeJSON
func (Document) Elems ¶
Elems returns all elements in an array.
Iteration order is stable and honors the original ordering in which elements were declared.
func (Document) Encode ¶
Encode the Document as a JSON stream to an io.Writer.
TODO: should renamed EncodeJSON
func (Document) GetPointer ¶
GetPointer returns the JSON Document pointed by a JSON Pointer inside the current Document, or an error if it is not found.
func (Document) JSONLookup ¶
JSONLookup implements the classical github.com/go-openapi/jsonpointer.JSONPointable interface, so users of this package can resolve JSON pointers against Document s.
The returned value is always a JSON Document.
func (Document) LexerFactory ¶
func (Document) LexerFromReaderFactory ¶
func (Document) MarshalJSON ¶
MarshalJSON writes the Document as JSON bytes.
func (*Document) Node ¶
Node low-level access to the current node in the document hierarchy.
Most users won't need this "backdoor" to the internal node representation of the Document. It is however necessary when constructing constrained types on top of the Document type.
See github.com/fredbi/core/json/constrained.Object for an example.
func (Document) Pairs ¶
Pairs return all (key,Node) pairs inside an object.
Iteration order is stable and honors the original ordering in which keys were declared.
func (*Document) UnmarshalJSON ¶
UnmarshalJSON builds a Document from JSON bytes.
func (Document) WriterToWriterFactory ¶
func (o Document) WriterToWriterFactory() func(io.Writer) (writers.StoreWriter, func())
type DocumentFactory ¶
type DocumentFactory struct {
// contains filtered or unexported fields
}
DocumentFactory is a factory that produces Document s with the same settings.
TODO: the idea with a factory is to be able to keep track of all things generated so we may recycle them
func NewDocumentFactory ¶
func NewDocumentFactory(opts ...Option) *DocumentFactory
NewDocumentFactory builds a factory for Document s
func (DocumentFactory) Clone ¶
func (f DocumentFactory) Clone(d Document) Document
func (DocumentFactory) Empty ¶
func (f DocumentFactory) Empty() Document
func (DocumentFactory) LexerFactory ¶
func (DocumentFactory) LexerFromReaderFactory ¶
func (DocumentFactory) WriterToWriterFactory ¶
func (o DocumentFactory) WriterToWriterFactory() func(io.Writer) (writers.StoreWriter, func())
type Option ¶
type Option func(*options)
func WithWriter ¶
func WithWriter(w writers.StoreWriter) Option
type Pointer ¶
type Pointer []stringOrInt
Pointer represents a JSON Pointer.
func MakePointer ¶
MakePointer builds a JSON Pointer from its string representation.
RFC6901 definition of a JSON pointer:
- may be empty
- if not empty, must start by "/"
- all tokens are separated by "/"
- "/" is escaped by "~1"
- "~" is escaped by "~0"
- tokens representing a numerical array index are non-negative integers
- an integer digit may be "0" or any integer without a leading "0"
Notice that this definition of a JSON pointer does not yield a unique match: token "123" would both match key "123" in an object or item 123 in an array.
func MakePointerFromElements ¶
MakePointerFromElements buils a JSON Pointer from a list of elements that constitute the search path.
Elements may be of type string, values.InternedKey or int.
String elements are not escaped.
Integer elements only apply to arrays. In this representation, we no longer have an ambiguous search that could match a key with the string representation of the integer element.
type VerbatimDocument ¶
type VerbatimDocument struct {
}
VerbatimDocument holds a JSON document verbatim.
All original marks kepts, including non-significant white space and escaped unicode points.
TODO(fred)
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package constrained exposes constrained json.Document types.
|
Package constrained exposes constrained json.Document types. |
|
Package dynamic converts a json.Document to dynamic JSON and vice versa.
|
Package dynamic converts a json.Document to dynamic JSON and vice versa. |
|
Package lexers exposes interfaces for lexing JSON.
|
Package lexers exposes interfaces for lexing JSON. |
|
default-lexer
Package lexer provides a JSON lexer.
|
Package lexer provides a JSON lexer. |
|
error-codes
Package codes exposes common lexer errors.
|
Package codes exposes common lexer errors. |
|
ld-lexer
Package lexer exposes lexer for ld-json (line-delimited JSON).
|
Package lexer exposes lexer for ld-json (line-delimited JSON). |
|
token
Package token defines the JSON token types with their kind.
|
Package token defines the JSON token types with their kind. |
|
Package nodes declares node types for JSON documents.
|
Package nodes declares node types for JSON documents. |
|
light
Package light exposes an implementation for nodes.
|
Package light exposes an implementation for nodes. |
|
Package stores exposes the interface to work with a JSON Store.
|
Package stores exposes the interface to work with a JSON Store. |
|
default-store
Package store provides default implementations for stores.Store.
|
Package store provides default implementations for stores.Store. |
|
Package types defines common types to work with json.
|
Package types defines common types to work with json. |
|
Package writers exposes interfaces to write JSON data.
|
Package writers exposes interfaces to write JSON data. |
|
default-writer
Package writer exposes an implementation of the JSON writer interface writers.Writer.
|
Package writer exposes an implementation of the JSON writer interface writers.Writer. |