Help us shape the future of Go! Take the 2026 Go Developer Survey

json

package module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2023 License: GPL-3.0 Imports: 3 Imported by: 0

README

Documentation Go workflow CircleCI codecov GolangCI Go Report Card GitHub tag (latest SemVer)

json

This is one more json library. It's created to process unstructured json in a convenient and efficient way.

There is also some set of jq filters implemented on top of json.Parser.

usage

Parser is stateless. Most of the methods take source buffer and index where to start parsing and return a result and index where they stopped parsing.

// Parsing single object.

var p json.Parser
data := []byte(`{"key": "value", "another": 1234}`)

i := 0 // initial position
i, err := p.Enter(data, i, json.Object)
if err != nil {
	// not an object
}

var key []byte // to not to shadow i and err in a loop

// extracted values
var value, another []byte

for p.ForMore(data, &i, json.Object, &err) {
	key, i, err = p.Key(data, i) // key decodes a string but don't decode '\n', '\"', '\xXX' and others
	if err != nil {
		// ...
	}

	switch string(key) {
	case "key":
		value, i, err = p.DecodeString(data, i, value[:0]) // reuse value buffer if we are in a loop or something
	case "another":
		another, i, err = p.Raw(data, i)
	default: // skip additional keys
		i, err = p.Skip(data, i)
	}

	// check error for all switch cases
	if err != nil {
		// ...
	}
}
if err != nil {
	// ForMore error
}
// Parsing jsonl: newline (or space, or comma) delimited values.

var err error // to not to shadow i in a loop
var p json.Parser
data := []byte(`"a", 2 3
["array"]
`)

for i := 0; i < len(data); i = p.SkipSpaces(data, i) { // eat trailing spaces and not try to read the value from string "\n"
	i, err = processOneObject(data, i) // do not use := here as it shadow i and loop will restart from the same index
	if err != nil {
		// ...
	}
}

jq usage

jq package is a set of Filters that take data from one buffer, process it, and add result to another buffer. Filters take destination buffer, source buffer, and starting index in a source buffer and return updated destination buffer, ending index, and possible error.

Destination buffer is returned even in case of error. This is mostly for avoiding allocs in case the buffer was grown but error happened.

// Extract some inside value.

data := []byte(`{"key0":"skip it", "key1": {"next_key": ["array", null, {"obj":"val"}, "trailing element"]}}  "next"`)

f := jq.Selector{"key1", "next_key", 2} // string keys and int array indexes are supported

var res []byte // reusable buffer
var i int      // start index

// Most filters only parse single value and return index where the value ended.
// Use jq.ApplyToAll(f, res[:0], data, 0) to process all values in a buffer.
res, i, err := f.Apply(res[:0], data, i)
if err != nil {
	// i is an index in a source buffer where the error occured.
}

fmt.Printf("value: %s", res)                           // res ends on newline
fmt.Printf("final position: %d of %d\n", i, len(data)) // object was parsed to the end to be able to read next
_ = data                                               // but not the next value

Documentation

Index

Examples

Constants

View Source
const (
	None   = 0
	Null   = 'n'
	Bool   = 'b'
	String = 's'
	Array  = '['
	Object = '{'
	Number = 'N'
)

Variables

View Source
var (
	ErrEndOfBuffer = errors.New("unexpected end of buffer")
	ErrSyntax      = errors.New("syntax error")
	ErrBadString   = errors.New("bad string")
	ErrBadRune     = errors.New("bad rune")
	ErrType        = errors.New("incompatible type")
)

Functions

func SkipSpaces added in v0.4.0

func SkipSpaces(b []byte, i int) int

Types

type Generator added in v0.4.0

type Generator struct{}

func (*Generator) EncodeString added in v0.4.0

func (g *Generator) EncodeString(w, s []byte) []byte

func (*Generator) EncodeStringContent added in v0.4.0

func (g *Generator) EncodeStringContent(w, s []byte) []byte

type Parser added in v0.4.0

type Parser struct{}
Example
package main

import (
	"fmt"

	"github.com/nikandfor/json"
)

func main() {
	var p json.Parser
	data := []byte(`{"key": "value", "another": 1234}`)

	i := 0 // initial position
	i, err := p.Enter(data, i, json.Object)
	if err != nil {
		// not an object
	}

	var key []byte // to not to shadow i and err in a loop

	// extracted values
	var value, another []byte

	for p.ForMore(data, &i, json.Object, &err) {
		key, i, err = p.Key(data, i) // key decodes a string but don't decode '\n', '\"', '\xXX' and others
		if err != nil {
			// ...
		}

		switch string(key) {
		case "key":
			value, i, err = p.DecodeString(data, i, value[:0]) // reuse value buffer if we are in a loop or something
		case "another":
			another, i, err = p.Raw(data, i)
		default: // skip additional keys
			i, err = p.Skip(data, i)
		}

		// check error for all switch cases
		if err != nil {
			// ...
		}
	}
	if err != nil {
		// ForMore error
	}

	fmt.Printf("key: %s\nanother: %s\n", value, another)

}
Output:
key: value
another: 1234
Example (MultipleValues)
package main

import (
	"fmt"

	"github.com/nikandfor/json"
)

func main() {
	var err error // to not to shadow i in a loop
	var p json.Parser
	data := []byte(`"a", 2 3
["array"]
`)

	processOneObject := func(data []byte, st int) (int, error) {
		raw, i, err := p.Raw(data, st)

		fmt.Printf("value: %s\n", raw)

		return i, err
	}

	for i := 0; i < len(data); i = p.SkipSpaces(data, i) { // eat trailing spaces and not try to read the value from string "\n"
		i, err = processOneObject(data, i) // do not use := here as it shadow i and loop will restart from the same index
		if err != nil {
			// ...
		}
	}

}
Output:
value: "a"
value: 2
value: 3
value: ["array"]

func (*Parser) Break added in v0.4.0

func (p *Parser) Break(b []byte, st, depth int) (i int, err error)

func (*Parser) DecodeString added in v0.4.0

func (p *Parser) DecodeString(b []byte, st int, buf []byte) (s []byte, i int, err error)

func (*Parser) DecodedStringLength added in v0.4.0

func (p *Parser) DecodedStringLength(b []byte, st int) (n, i int, err error)

func (*Parser) Enter added in v0.4.0

func (p *Parser) Enter(b []byte, st int, typ byte) (i int, err error)

func (*Parser) ForMore added in v0.4.0

func (p *Parser) ForMore(b []byte, i *int, typ byte, errp *error) bool

func (*Parser) Key added in v0.4.0

func (p *Parser) Key(b []byte, st int) (k []byte, i int, err error)

func (*Parser) Length added in v0.4.0

func (p *Parser) Length(b []byte, st int) (n, i int, err error)

func (*Parser) More added in v0.4.0

func (p *Parser) More(b []byte, st int, typ byte) (more bool, i int, err error)

func (*Parser) Raw added in v0.4.0

func (p *Parser) Raw(b []byte, st int) (v []byte, i int, err error)

func (*Parser) Skip added in v0.4.0

func (p *Parser) Skip(b []byte, st int) (i int, err error)

func (*Parser) SkipSpaces added in v0.4.0

func (p *Parser) SkipSpaces(b []byte, i int) int

func (*Parser) Type added in v0.4.0

func (p *Parser) Type(b []byte, st int) (tp byte, i int, err error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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