oj

package
v1.22.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 28, 2024 License: MIT Imports: 19 Imported by: 59

Documentation

Overview

Package oj contains functions and types to support building simple types where simple types are:

nil
bool
int64
float64
string
time.Time
[]any
map[string]any

Parser

Parse a JSON file or stream. The parser can be used on a single JSON document or a document with multiple JSON elements. An option also exists to allow comments in the JSON.

v, err := oj.ParseString("[true,[false,[null],123],456]")

or for a performance gain on repeated parses:

var p oj.Parser
v, err := p.Parse([]byte("[true,[false,[null],123],456]"))

Validator

Validates a JSON file or stream. It can be used on a single JSON document or a document with multiple JSON elements. An option also exists to allow comments in the JSON.

err := oj.ValidateString("[true,[false,[null],123],456]")

or for a slight performance gain on repeated validations:

var v oj.Validator
err := v.Validate([]byte("[true,[false,[null],123],456]"))

Builder

An example of building simple data is:

var b oj.Builder

b.Object()
b.Value(1, "a")
b.Array("b")
b.Value(2)
b.Pop()
b.Pop()
v := b.Result()

// v: map[string]any{"a": 1, "b": []any{2}}

Writer

The writer function's output data values to JSON. The basic oj.JSON() attempts to build JSON from any data provided skipping types that can not be converted.

s := oj.JSON([]any{1, 2, "abc", true})

Output can also be use with an io.Writer.

var b strings.Builder

err := oj.Write(&b, []any{1, 2, "abc", true})

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// DefaultOptions are the default options for the this package.
	DefaultOptions = ojg.DefaultOptions
	// BrightOptions are the bright color options.
	BrightOptions = ojg.BrightOptions

	// HTMLOptions are the options that can be used to encode as HTML JSON.
	HTMLOptions = ojg.HTMLOptions
)

Functions

func JSON

func JSON(data any, args ...any) string

JSON returns a JSON string for the data provided. The data can be a simple type of nil, bool, int, floats, time.Time, []any, or map[string]any or a Node type, The args, if supplied can be an int as an indent or a *Options.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
)

func main() {
	type Valley struct {
		Val int `json:"value"`
	}
	b := oj.JSON(&Valley{Val: 3})
	fmt.Printf("%s\n", b)
}
Output:

{"val":3}

func Load

func Load(r io.Reader, args ...any) (any, error)

Load a JSON from a io.Reader into a simple type. An error is returned if not valid JSON.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/ohler55/ojg/oj"
	"github.com/ohler55/ojg/pretty"
)

func main() {
	r := strings.NewReader(`[true,false,[3,2,1],{"a":1,"b":2,"c":3,"d":["x","y","z",[]]}]`)
	val, err := oj.Load(r)
	if err != nil {
		panic(err)
	}
	fmt.Println(pretty.JSON(val, 80.3))

}
Output:

[
  true,
  false,
  [3, 2, 1],
  {"a": 1, "b": 2, "c": 3, "d": ["x", "y", "z", []]}
]

func Marshal added in v1.3.0

func Marshal(data any, args ...any) (out []byte, err error)

Marshal returns a JSON string for the data provided. The data can be a simple type of nil, bool, int, floats, time.Time, []any, or map[string]any or a gen.Node type, The args, if supplied can be an int as an indent, *ojg.Options, or a *Writer. An error will be returned if the Option.Strict flag is true and a value is encountered that can not be encoded other than by using the %v format of the fmt package.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
)

func main() {
	type Valley struct {
		Val int `json:"value"`
	}
	b, err := oj.Marshal(&Valley{Val: 3})
	fmt.Printf("%v %s\n", err, b)
}
Output:

<nil> {"value":3}

func MustLoad added in v1.11.0

func MustLoad(r io.Reader, args ...any) (n any)

MustLoad a JSON from a io.Reader into a simple type. Panics on error.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/ohler55/ojg/oj"
	"github.com/ohler55/ojg/pretty"
)

func main() {
	r := strings.NewReader(`[true,false,[3,2,1],{"a":1,"b":2,"c":3,"d":["x","y","z",[]]}]`)
	val := oj.MustLoad(r)
	fmt.Println(pretty.JSON(val, 80.3))

}
Output:

[
  true,
  false,
  [3, 2, 1],
  {"a": 1, "b": 2, "c": 3, "d": ["x", "y", "z", []]}
]

func MustParse added in v1.11.0

func MustParse(b []byte, args ...any) (n any)

MustParse JSON into a simple type. Arguments are optional and can be a bool, func(any) bool for callbacks, or a chan any for chan based result delivery. Panics on error

A bool indicates the NoComment parser attribute should be set to the bool value.

A func argument is the callback for the parser if processing multiple JSONs. If no callback function is provided the processing is limited to only one JSON.

A chan argument will be used to deliver parse results.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
	"github.com/ohler55/ojg/pretty"
)

func main() {
	val := oj.MustParse([]byte(`[true,false,[3,2,1],{"a":1,"b":2,"c":3,"d":["x","y","z",[]]}]`))
	fmt.Println(pretty.JSON(val, 80.3))

}
Output:

[
  true,
  false,
  [3, 2, 1],
  {"a": 1, "b": 2, "c": 3, "d": ["x", "y", "z", []]}
]

func MustParseString added in v1.11.0

func MustParseString(s string, args ...any) (n any)

MustParseString is similar to MustParse except it takes a string argument to be parsed instead of a []byte.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
	"github.com/ohler55/ojg/pretty"
)

func main() {
	val := oj.MustParseString(`[true,false,[3,2,1],{"a":1,"b":2,"c":3,"d":["x","y","z",[]]}]`)
	fmt.Println(pretty.JSON(val, 80.3))

}
Output:

[
  true,
  false,
  [3, 2, 1],
  {"a": 1, "b": 2, "c": 3, "d": ["x", "y", "z", []]}
]

func Parse

func Parse(b []byte, args ...any) (n any, err error)

Parse JSON into a simple type. Arguments are optional and can be a bool, func(any) bool for callbacks, or a chan any for chan based result delivery.

A bool indicates the NoComment parser attribute should be set to the bool value.

A func argument is the callback for the parser if processing multiple JSONs. If no callback function is provided the processing is limited to only one JSON.

A chan argument will be used to deliver parse results.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
	"github.com/ohler55/ojg/pretty"
)

func main() {
	val, err := oj.Parse([]byte(`[true,false,[3,2,1],{"a":1,"b":2,"c":3,"d":["x","y","z",[]]}]`))
	if err != nil {
		panic(err)
	}
	fmt.Println(pretty.JSON(val, 80.3))

}
Output:

[
  true,
  false,
  [3, 2, 1],
  {"a": 1, "b": 2, "c": 3, "d": ["x", "y", "z", []]}
]

func ParseString

func ParseString(s string, args ...any) (n any, err error)

ParseString is similar to Parse except it takes a string argument to be parsed instead of a []byte.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
)

func main() {
	v, err := oj.ParseString(`{"a": 1, "b":[2,3,4]}`)
	if err == nil {
		// Sorted output allows for consistent results.
		fmt.Println(oj.JSON(v, &oj.Options{Sort: true}))
	} else {
		fmt.Println(err.Error())
	}
}
Output:

{"a":1,"b":[2,3,4]}

func Tokenize added in v1.10.0

func Tokenize(data []byte, handler TokenHandler) error

Tokenize the provided JSON and call the TokenHandler functions for each token in the JSON.

func TokenizeLoad added in v1.10.0

func TokenizeLoad(r io.Reader, handler TokenHandler) error

TokenizeLoad JSON from a io.Reader and call the TokenHandler functions for each token in the JSON.

func TokenizeString added in v1.10.0

func TokenizeString(data string, handler TokenHandler) error

TokenizeString the provided JSON and call the handler functions for each token in the JSON.

func Unmarshal added in v1.9.0

func Unmarshal(data []byte, vp any, recomposer ...*alt.Recomposer) (err error)

Unmarshal parses the provided JSON and stores the result in the value pointed to by vp.

Example (Interface)
package main

import (
	"fmt"

	"github.com/ohler55/ojg"
	"github.com/ohler55/ojg/alt"
	"github.com/ohler55/ojg/oj"
)

// Encode and decode slice of interfaces.

type Animal interface {
	Kind() string
}

type Dog struct {
	Size string
}

func (d *Dog) Kind() string {
	return fmt.Sprintf("%s dog", d.Size)
}

type Cat struct {
	Color string
}

func (c *Cat) Kind() string {
	return fmt.Sprintf("%s cat", c.Color)
}

func main() {
	pets := []Animal{&Dog{Size: "big"}, &Cat{Color: "black"}}

	// Encode and use a create key to identify the encoded type.
	b, err := oj.Marshal(pets, &ojg.Options{CreateKey: "^", Sort: true})
	if err != nil {
		panic(err)
	}
	// Sort the object members in the output for repeatability.
	fmt.Printf("as JSON: %s\n", b)

	// Create a new Recomposer. This can be use over and over again. Register
	// the types with a nil creation function to let reflection do the work
	// since the types are exported.
	var r *alt.Recomposer
	if r, err = alt.NewRecomposer("^", map[any]alt.RecomposeFunc{&Dog{}: nil, &Cat{}: nil}); err != nil {
		panic(err)
	}
	var result any
	if err = oj.Unmarshal(b, &result, r); err != nil {
		panic(err)
	}
	list, _ := result.([]any)
	for _, item := range list {
		animal, _ := item.(Animal)
		fmt.Printf("  %s\n", animal.Kind())
	}
	// Unmarshal with a typed target.
	var animals []Animal
	if err = oj.Unmarshal(b, &animals, r); err != nil {
		panic(err)
	}
	fmt.Println("Unmarshal into a target struct")
	for _, animal := range animals {
		fmt.Printf("  %T - %s\n", animal, animal.Kind())
	}

}
Output:

as JSON: [{"^":"Dog","size":"big"},{"^":"Cat","color":"black"}]
  big dog
  black cat
Unmarshal into a target struct
  *oj_test.Dog - big dog
  *oj_test.Cat - black cat

func Validate

func Validate(b []byte) error

Validate a JSON string. An error is returned if not valid JSON.

func ValidateReader

func ValidateReader(r io.Reader) error

ValidateReader a JSON stream. An error is returned if not valid JSON.

func ValidateString

func ValidateString(s string) error

ValidateString a JSON string. An error is returned if not valid JSON.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
)

func main() {
	err := oj.ValidateString(`{"a": 1, "b":[2,3,4]}`)
	fmt.Println(oj.JSON(err))
}
Output:

null

func Write

func Write(w io.Writer, data any, args ...any) (err error)

Write a JSON string for the data provided. The data can be a simple type of nil, bool, int, floats, time.Time, []any, or map[string]any or a Node type, The args, if supplied can be an int as an indent or a *Options.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/ohler55/ojg"
	"github.com/ohler55/ojg/oj"
)

func main() {
	var b strings.Builder
	data := []any{
		map[string]any{
			"x": 1,
			"y": 2,
		},
	}
	if err := oj.Write(&b, data, &ojg.Options{Sort: true}); err != nil {
		panic(err)
	}
	fmt.Println(b.String())

}
Output:

[{"x":1,"y":2}]

Types

type Builder

type Builder = alt.Builder

Builder is an aliase for alt.Builder.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
)

func main() {
	var b oj.Builder

	_ = b.Object()
	_ = b.Array("a")
	_ = b.Value(true)
	_ = b.Object()
	_ = b.Value(123, "x")
	b.Pop()
	_ = b.Value(nil)
	b.PopAll()
	v := b.Result()
	fmt.Println(oj.JSON(v))
}
Output:

{"a":[true,{"x":123},null]}

type Options

type Options = ojg.Options

Options is an alias for ojg.Options

type ParseError

type ParseError struct {
	Message string
	Line    int
	Column  int
}

ParseError represents a parse error.

func (*ParseError) Error

func (err *ParseError) Error() string

Error returns a string representation of the error.

type Parser

type Parser struct {

	// Reuse maps. Previously returned maps will no longer be valid or rather
	// could be modified during parsing.
	Reuse bool
	// contains filtered or unexported fields
}

Parser is a reusable JSON parser. It can be reused for multiple parsings which allows buffer reuse for a performance advantage.

func (*Parser) Parse

func (p *Parser) Parse(buf []byte, args ...any) (any, error)

Parse a JSON string in to simple types. An error is returned if not valid JSON.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
)

func main() {
	// The parser can be reused for better performance by reusing buffers.
	var p oj.Parser
	v, err := p.Parse([]byte(`{"a": 1, "b":[2,3,4]}`))
	if err == nil {
		// Sorted output allows for consistent results.
		fmt.Println(oj.JSON(v, &oj.Options{Sort: true}))
	} else {
		fmt.Println(err.Error())
	}
}
Output:

{"a":1,"b":[2,3,4]}
Example (Callback)
package main

import (
	"fmt"

	"github.com/ohler55/ojg/oj"
)

func main() {
	var results []byte
	cb := func(n any) bool {
		if 0 < len(results) {
			results = append(results, ' ')
		}
		results = append(results, oj.JSON(n)...)
		return false
	}
	var p oj.Parser
	_, _ = p.Parse([]byte("[1,2][3,4][5,6]"), cb)
	fmt.Println(string(results))
}
Output:

[1,2] [3,4] [5,6]

func (*Parser) ParseReader

func (p *Parser) ParseReader(r io.Reader, args ...any) (data any, err error)

ParseReader reads JSON from an io.Reader. An error is returned if not valid JSON.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/ohler55/ojg/oj"
)

func main() {
	// The parser can be reused for better performance by reusing buffers.
	var p oj.Parser
	v, err := p.ParseReader(strings.NewReader(`{"a": 1, "b":[2,3,4]}`))
	if err == nil {
		// Sorted output allows for consistent results.
		fmt.Println(oj.JSON(v, &oj.Options{Sort: true}))
	} else {
		fmt.Println(err.Error())
	}
}
Output:

{"a":1,"b":[2,3,4]}

func (*Parser) Unmarshal added in v1.9.0

func (p *Parser) Unmarshal(data []byte, vp any, recomposer ...alt.Recomposer) (err error)

Unmarshal parses the provided JSON and stores the result in the value pointed to by vp.

type SimpleParser added in v1.1.0

type SimpleParser interface {
	// Parse a string in to simple types. An error is returned if not valid.
	Parse(buf []byte, args ...any) (data any, err error)

	// ParseReader an io.Reader. An error is returned if not valid.
	ParseReader(r io.Reader, args ...any) (node any, err error)
}

SimpleParser is the interface shared by the package parsers.

type TokenHandler added in v1.10.0

type TokenHandler interface {
	// Null is called when a JSON null is encountered.
	Null()

	// Bool is called when a JSON true or false is encountered.
	Bool(bool)

	// Int is called when a JSON integer is encountered.
	Int(int64)

	// Float is called when a JSON decimal is encountered that fits into a
	// float64.
	Float(float64)

	// Number is called when a JSON number is encountered that does not fit
	// into an int64 or float64.
	Number(string)

	// String is called when a JSON string is encountered.
	String(string)

	// ObjectStart is called when a JSON object start '{' is encountered.
	ObjectStart()

	// ObjectEnd is called when a JSON object end '}' is encountered.
	ObjectEnd()

	// Key is called when a JSON object key is encountered.
	Key(string)

	// ArrayStart is called when a JSON array start '[' is encountered.
	ArrayStart()

	// ArrayEnd is called when a JSON array end ']' is encountered.
	ArrayEnd()
}

TokenHandler describes an interface for handling tokens when using the Tokenizer for parsing JSON or SEN documents.

type Tokenizer added in v1.10.0

type Tokenizer struct {
	// contains filtered or unexported fields
}

Tokenizer is used to tokenize a JSON document.

func (*Tokenizer) Load added in v1.10.0

func (t *Tokenizer) Load(r io.Reader, handler TokenHandler) (err error)

Load aand parse the JSON and call the handler functions for each token in the JSON.

func (*Tokenizer) Parse added in v1.10.0

func (t *Tokenizer) Parse(buf []byte, handler TokenHandler) (err error)

Parse the JSON and call the handler functions for each token in the JSON.

Example
package main

import (
	"bytes"
	"fmt"

	"github.com/ohler55/ojg/oj"
)

type Toker struct {
	buf []byte
}

func (h *Toker) Null() {
	h.buf = append(h.buf, "null "...)
}

func (h *Toker) Bool(v bool) {
	h.buf = append(h.buf, fmt.Sprintf("%t ", v)...)
}

func (h *Toker) Int(v int64) {
	h.buf = append(h.buf, fmt.Sprintf("%d ", v)...)
}

func (h *Toker) Float(v float64) {
	h.buf = append(h.buf, fmt.Sprintf("%g ", v)...)
}

func (h *Toker) Number(v string) {
	h.buf = append(h.buf, fmt.Sprintf("%s ", v)...)
}

func (h *Toker) String(v string) {
	h.buf = append(h.buf, fmt.Sprintf("%s ", v)...)
}

func (h *Toker) ObjectStart() {
	h.buf = append(h.buf, '{')
	h.buf = append(h.buf, ' ')
}

func (h *Toker) ObjectEnd() {
	h.buf = append(h.buf, '}')
	h.buf = append(h.buf, ' ')
}

func (h *Toker) Key(v string) {
	h.buf = append(h.buf, fmt.Sprintf("%s: ", v)...)
}

func (h *Toker) ArrayStart() {
	h.buf = append(h.buf, '[')
	h.buf = append(h.buf, ' ')
}

func (h *Toker) ArrayEnd() {
	h.buf = append(h.buf, ']')
	h.buf = append(h.buf, ' ')
}

func main() {
	toker := oj.Tokenizer{}
	h := Toker{}
	src := `[true,null,123,12.3]{"x":12345678901234567890}`
	if err := toker.Parse([]byte(src), &h); err != nil {
		panic(err)
	}
	fmt.Println(string(bytes.TrimSpace(h.buf)))

}
Output:

[ true null 123 12.3 ] { x: 12345678901234567890 }

type Validator

type Validator struct {

	// OnlyOne returns an error if more than one JSON is in the string or
	// stream.
	OnlyOne bool
	// contains filtered or unexported fields
}

Validator is a reusable JSON validator. It can be reused for multiple validations or parsings which allows buffer reuse for a performance advantage.

func (*Validator) Validate

func (p *Validator) Validate(buf []byte) (err error)

Validate a JSON encoded byte slice.

func (*Validator) ValidateReader

func (p *Validator) ValidateReader(r io.Reader) error

ValidateReader a JSON stream. An error is returned if not valid JSON.

type Writer added in v1.11.0

type Writer struct {
	ojg.Options
	// contains filtered or unexported fields
}

Writer is a JSON writer that includes a reused buffer for reduced allocations for repeated encoding calls.

func (*Writer) JSON added in v1.11.0

func (wr *Writer) JSON(data any) string

JSON writes data, JSON encoded. On error, an empty string is returned.

Example
package main

import (
	"fmt"

	"github.com/ohler55/ojg"
	"github.com/ohler55/ojg/oj"
)

func main() {
	data := []any{
		map[string]any{
			"x": 1,
			"y": 2,
		},
	}
	wr := oj.Writer{Options: ojg.Options{Sort: true}}
	j := wr.JSON(data)
	fmt.Println(j)

}
Output:

[{"x":1,"y":2}]

func (*Writer) MustJSON added in v1.11.0

func (wr *Writer) MustJSON(data any) []byte

MustJSON writes data, JSON encoded as a []byte and not a string like the JSON() function. On error a panic is called with the error. The returned buffer is the Writer buffer and is reused on the next call to write. If returned value is to be preserved past a second invocation then the buffer should be copied.

func (*Writer) MustWrite added in v1.11.0

func (wr *Writer) MustWrite(w io.Writer, data any)

MustWrite a JSON string for the data provided. If an error occurs panic is called with the error.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/ohler55/ojg"
	"github.com/ohler55/ojg/oj"
)

func main() {
	var b strings.Builder
	data := []any{
		map[string]any{
			"x": 1,
			"y": 2,
		},
	}
	wr := oj.Writer{Options: ojg.Options{Sort: true}}
	wr.MustWrite(&b, data)
	fmt.Println(b.String())

}
Output:

[{"x":1,"y":2}]

func (*Writer) Write added in v1.11.0

func (wr *Writer) Write(w io.Writer, data any) (err error)

Write a JSON string for the data provided.

type ZeroHandler added in v1.10.0

type ZeroHandler struct {
}

ZeroHandler is a TokenHandler whose functions do nothing. It is used as an embedded member for TokenHandlers that don't care about all of the TokenHandler functions.

func (*ZeroHandler) ArrayEnd added in v1.10.0

func (z *ZeroHandler) ArrayEnd()

ArrayEnd is called when a JSON array end ']' is encountered.

func (*ZeroHandler) ArrayStart added in v1.10.0

func (z *ZeroHandler) ArrayStart()

ArrayStart is called when a JSON array start '[' is encountered.

func (*ZeroHandler) Bool added in v1.10.0

func (z *ZeroHandler) Bool(bool)

Bool is called when a JSON true or false is encountered.

func (*ZeroHandler) Float added in v1.10.0

func (z *ZeroHandler) Float(float64)

Float is called when a JSON decimal is encountered that fits into a float64.

func (*ZeroHandler) Int added in v1.10.0

func (z *ZeroHandler) Int(int64)

Int is called when a JSON integer is encountered.

func (*ZeroHandler) Key added in v1.10.0

func (z *ZeroHandler) Key(string)

Key is called when a JSON object key is encountered.

func (*ZeroHandler) Null added in v1.10.0

func (z *ZeroHandler) Null()

Null is called when a JSON null is encountered.

func (*ZeroHandler) Number added in v1.10.0

func (z *ZeroHandler) Number(string)

Number is called when a JSON number is encountered that does not fit into an int64 or float64.

func (*ZeroHandler) ObjectEnd added in v1.10.0

func (z *ZeroHandler) ObjectEnd()

ObjectEnd is called when a JSON object end '}' is encountered.

func (*ZeroHandler) ObjectStart added in v1.10.0

func (z *ZeroHandler) ObjectStart()

ObjectStart is called when a JSON object start '{' is encountered.

func (*ZeroHandler) String added in v1.10.0

func (z *ZeroHandler) String(string)

String is called when a JSON string is encountered.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL