fastjson

package
v0.2.14 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2024 License: MIT, MIT Imports: 9 Imported by: 3

README

Build Status GoDoc Go Report codecov

fastjson - fast JSON parser and validator for Go

Features

  • Fast. As usual, up to 15x faster than the standard encoding/json. See benchmarks.
  • Parses arbitrary JSON without schema, reflection, struct magic and code generation contrary to easyjson.
  • Provides simple API.
  • Outperforms jsonparser and gjson when accessing multiple unrelated fields, since fastjson parses the input JSON only once.
  • Validates the parsed JSON unlike jsonparser and gjson.
  • May quickly extract a part of the original JSON with Value.Get(...).MarshalTo and modify it with Del and Set functions.
  • May parse array containing values with distinct types (aka non-homogenous types). For instance, fastjson easily parses the following JSON array [123, "foo", [456], {"k": "v"}, null].
  • fastjson preserves the original order of object items when calling Object.Visit.

Known limitations

  • Requies extra care to work with - references to certain objects recursively returned by Parser must be released before the next call to Parse. Otherwise the program may work improperly. The same applies to objects returned by Arena. Adhere recommendations from docs.
  • Cannot parse JSON from io.Reader. There is Scanner for parsing stream of JSON values from a string.

Usage

One-liner accessing a single field:

    s := []byte(`{"foo": [123, "bar"]}`)
fmt.Printf("foo.0=%d\n", fastjson.GetInt(s, "foo", "0"))

// Output:
// foo.0=123

Accessing multiple fields with error handling:

        var p fastjson.Parser
v, err := p.Parse(`{
                "str": "bar",
                "int": 123,
                "float": 1.23,
                "bool": true,
                "arr": [1, "foo", {}]
        }`)
if err != nil {
log.Fatal(err)
}
fmt.Printf("foo=%s\n", v.GetStringBytes("str"))
fmt.Printf("int=%d\n", v.GetInt("int"))
fmt.Printf("float=%f\n", v.GetFloat64("float"))
fmt.Printf("bool=%v\n", v.GetBool("bool"))
fmt.Printf("arr.1=%s\n", v.GetStringBytes("arr", "1"))

// Output:
// foo=bar
// int=123
// float=1.230000
// bool=true
// arr.1=foo

See also examples.

Security

  • fastjson shouldn't crash or panic when parsing input strings specially crafted by an attacker. It must return error on invalid input JSON.
  • fastjson requires up to sizeof(Value) * len(inputJSON) bytes of memory for parsing inputJSON string. Limit the maximum size of the inputJSON before parsing it in order to limit the maximum memory usage.

Performance optimization tips

  • Re-use Parser and Scanner for parsing many JSONs. This reduces memory allocations overhead. ParserPool may be useful in this case.
  • Prefer calling Value.Get* on the value returned from Parser instead of calling Get* one-liners when multiple fields must be obtained from JSON, since each Get* one-liner re-parses the input JSON again.
  • Prefer calling once Value.Get for common prefix paths and then calling Value.Get* on the returned value for distinct suffix paths.
  • Prefer iterating over array returned from Value.GetArray with a range loop instead of calling Value.Get* for each array item.

Fuzzing

Install go-fuzz & optionally the go-fuzz-corpus.

go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build

Build using go-fuzz-build and run go-fuzz with an optional corpus.

mkdir -p workdir/corpus
cp $GOPATH/src/github.com/dvyukov/go-fuzz-corpus/json/corpus/* workdir/corpus
go-fuzz-build github.com/valyala/fastjson
go-fuzz -bin=fastjson-fuzz.zip -workdir=workdir

Benchmarks

Go 1.12 has been used for benchmarking.

Legend:

  • small - parse small.json (190 bytes).

  • medium - parse medium.json (2.3KB).

  • large - parse large.json (28KB).

  • canada - parse canada.json (2.2MB).

  • citm - parse citm_catalog.json (1.7MB).

  • twitter - parse twitter.json (617KB).

  • stdjson-map - parse into a map[string]interface{} using encoding/json.

  • stdjson-struct - parse into a struct containing a subset of fields of the parsed JSON, using encoding/json.

  • stdjson-empty-struct - parse into an empty struct using encoding/json. This is the fastest possible solution for encoding/json, may be used for json validation. See also benchmark results for json validation.

  • fastjson - parse using fastjson without fields access.

  • fastjson-get - parse using fastjson with fields access similar to stdjson-struct.

$ GOMAXPROCS=1 go test github.com/valyala/fastjson -bench='Parse$'
goos: linux
goarch: amd64
pkg: github.com/valyala/fastjson
BenchmarkParse/small/stdjson-map         	  200000	      7305 ns/op	  26.01 MB/s	     960 B/op	      51 allocs/op
BenchmarkParse/small/stdjson-struct      	  500000	      3431 ns/op	  55.37 MB/s	     224 B/op	       4 allocs/op
BenchmarkParse/small/stdjson-empty-struct         	  500000	      2273 ns/op	  83.58 MB/s	     168 B/op	       2 allocs/op
BenchmarkParse/small/fastjson                     	 5000000	       347 ns/op	 547.53 MB/s	       0 B/op	       0 allocs/op
BenchmarkParse/small/fastjson-get                 	 2000000	       620 ns/op	 306.39 MB/s	       0 B/op	       0 allocs/op
BenchmarkParse/medium/stdjson-map                 	   30000	     40672 ns/op	  57.26 MB/s	   10196 B/op	     208 allocs/op
BenchmarkParse/medium/stdjson-struct              	   30000	     47792 ns/op	  48.73 MB/s	    9174 B/op	     258 allocs/op
BenchmarkParse/medium/stdjson-empty-struct        	  100000	     22096 ns/op	 105.40 MB/s	     280 B/op	       5 allocs/op
BenchmarkParse/medium/fastjson                    	  500000	      3025 ns/op	 769.90 MB/s	       0 B/op	       0 allocs/op
BenchmarkParse/medium/fastjson-get                	  500000	      3211 ns/op	 725.20 MB/s	       0 B/op	       0 allocs/op
BenchmarkParse/large/stdjson-map                  	    2000	    614079 ns/op	  45.79 MB/s	  210734 B/op	    2785 allocs/op
BenchmarkParse/large/stdjson-struct               	    5000	    298554 ns/op	  94.18 MB/s	   15616 B/op	     353 allocs/op
BenchmarkParse/large/stdjson-empty-struct         	    5000	    268577 ns/op	 104.69 MB/s	     280 B/op	       5 allocs/op
BenchmarkParse/large/fastjson                     	   50000	     35210 ns/op	 798.56 MB/s	       5 B/op	       0 allocs/op
BenchmarkParse/large/fastjson-get                 	   50000	     35171 ns/op	 799.46 MB/s	       5 B/op	       0 allocs/op
BenchmarkParse/canada/stdjson-map                 	      20	  68147307 ns/op	  33.03 MB/s	12260502 B/op	  392539 allocs/op
BenchmarkParse/canada/stdjson-struct              	      20	  68044518 ns/op	  33.08 MB/s	12260123 B/op	  392534 allocs/op
BenchmarkParse/canada/stdjson-empty-struct        	     100	  17709250 ns/op	 127.11 MB/s	     280 B/op	       5 allocs/op
BenchmarkParse/canada/fastjson                    	     300	   4182404 ns/op	 538.22 MB/s	  254902 B/op	     381 allocs/op
BenchmarkParse/canada/fastjson-get                	     300	   4274744 ns/op	 526.60 MB/s	  254902 B/op	     381 allocs/op
BenchmarkParse/citm/stdjson-map                   	      50	  27772612 ns/op	  62.19 MB/s	 5214163 B/op	   95402 allocs/op
BenchmarkParse/citm/stdjson-struct                	     100	  14936191 ns/op	 115.64 MB/s	    1989 B/op	      75 allocs/op
BenchmarkParse/citm/stdjson-empty-struct          	     100	  14946034 ns/op	 115.56 MB/s	     280 B/op	       5 allocs/op
BenchmarkParse/citm/fastjson                      	    1000	   1879714 ns/op	 918.87 MB/s	   17628 B/op	      30 allocs/op
BenchmarkParse/citm/fastjson-get                  	    1000	   1881598 ns/op	 917.94 MB/s	   17628 B/op	      30 allocs/op
BenchmarkParse/twitter/stdjson-map                	     100	  11289146 ns/op	  55.94 MB/s	 2187878 B/op	   31266 allocs/op
BenchmarkParse/twitter/stdjson-struct             	     300	   5779442 ns/op	 109.27 MB/s	     408 B/op	       6 allocs/op
BenchmarkParse/twitter/stdjson-empty-struct       	     300	   5738504 ns/op	 110.05 MB/s	     408 B/op	       6 allocs/op
BenchmarkParse/twitter/fastjson                   	    2000	    774042 ns/op	 815.86 MB/s	    2541 B/op	       2 allocs/op
BenchmarkParse/twitter/fastjson-get               	    2000	    777833 ns/op	 811.89 MB/s	    2541 B/op	       2 allocs/op

Benchmark results for json validation:

$ GOMAXPROCS=1 go test github.com/valyala/fastjson -bench='Validate$'
goos: linux
goarch: amd64
pkg: github.com/valyala/fastjson
BenchmarkValidate/small/stdjson 	 2000000	       955 ns/op	 198.83 MB/s	      72 B/op	       2 allocs/op
BenchmarkValidate/small/fastjson         	 5000000	       384 ns/op	 493.60 MB/s	       0 B/op	       0 allocs/op
BenchmarkValidate/medium/stdjson         	  200000	     10799 ns/op	 215.66 MB/s	     184 B/op	       5 allocs/op
BenchmarkValidate/medium/fastjson        	  300000	      3809 ns/op	 611.30 MB/s	       0 B/op	       0 allocs/op
BenchmarkValidate/large/stdjson          	   10000	    133064 ns/op	 211.31 MB/s	     184 B/op	       5 allocs/op
BenchmarkValidate/large/fastjson         	   30000	     45268 ns/op	 621.14 MB/s	       0 B/op	       0 allocs/op
BenchmarkValidate/canada/stdjson         	     200	   8470904 ns/op	 265.74 MB/s	     184 B/op	       5 allocs/op
BenchmarkValidate/canada/fastjson        	     500	   2973377 ns/op	 757.07 MB/s	       0 B/op	       0 allocs/op
BenchmarkValidate/citm/stdjson           	     200	   7273172 ns/op	 237.48 MB/s	     184 B/op	       5 allocs/op
BenchmarkValidate/citm/fastjson          	    1000	   1684430 ns/op	1025.39 MB/s	       0 B/op	       0 allocs/op
BenchmarkValidate/twitter/stdjson        	     500	   2849439 ns/op	 221.63 MB/s	     312 B/op	       6 allocs/op
BenchmarkValidate/twitter/fastjson       	    2000	   1036796 ns/op	 609.10 MB/s	       0 B/op	       0 allocs/op

FAQ

  • Q: There are a ton of other high-perf packages for JSON parsing in Go. Why creating yet another package? A: Because other packages require either rigid JSON schema via struct magic and code generation or perform poorly when multiple unrelated fields must be obtained from the parsed JSON. Additionally, fastjson provides nicer API.

  • Q: What is the main purpose for fastjson? A: High-perf JSON parsing for RTB and other JSON-RPC services.

  • Q: Why fastjson doesn't provide fast marshaling (serialization)? A: Actually it provides some sort of marshaling - see Value.MarshalTo. But I'd recommend using quicktemplate for high-performance JSON marshaling :)

  • Q: fastjson crashes my program! A: There is high probability of improper use.

    • Make sure you don't hold references to objects recursively returned by Parser / Scanner beyond the next Parser.Parse / Scanner.Next call if such restriction is mentioned in docs.
    • Make sure you don't access fastjson objects from concurrently running goroutines if such restriction is mentioned in docs.
    • Build and run your program with -race flag. Make sure the race detector detects zero races.
    • If your program continue crashing after fixing issues mentioned above, file a bug.

Documentation

Overview

Package fastjson provides fast JSON parsing.

Arbitrary JSON may be parsed by fastjson without the need for creating structs or for generating go code. Just parse JSON and get the required fields with Get* functions.

Index

Examples

Constants

View Source
const MaxDepth = 300

MaxDepth is the maximum depth for nested JSON.

Variables

This section is empty.

Functions

func Exists

func Exists(data []byte, keys ...string) bool

Exists returns true if the field identified by keys path exists in JSON data.

Array indexes may be represented as decimal numbers in keys.

False is returned on error. Use Parser for proper error handling.

Parser is faster when multiple fields must be checked in the JSON.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
)

func main() {
	data := []byte(`{"foo": [1.23,{"bar":33,"baz":null}]}`)

	fmt.Printf("exists(data.foo) = %v\n", fastjson.Exists(data, "foo"))
	fmt.Printf("exists(data.foo[0]) = %v\n", fastjson.Exists(data, "foo", "0"))
	fmt.Printf("exists(data.foo[1].baz) = %v\n", fastjson.Exists(data, "foo", "1", "baz"))
	fmt.Printf("exists(data.foobar) = %v\n", fastjson.Exists(data, "foobar"))
	fmt.Printf("exists(data.foo.bar) = %v\n", fastjson.Exists(data, "foo", "bar"))

}
Output:

exists(data.foo) = true
exists(data.foo[0]) = true
exists(data.foo[1].baz) = true
exists(data.foobar) = false
exists(data.foo.bar) = false

func GetBool

func GetBool(data []byte, keys ...string) bool

GetBool returns boolean value for the field identified by keys path in JSON data.

Array indexes may be represented as decimal numbers in keys.

False is returned on error. Use Parser for proper error handling.

Parser is faster for obtaining multiple fields from JSON.

func GetBytes

func GetBytes(data []byte, keys ...string) []byte

GetBytes returns string value for the field identified by keys path in JSON data.

Array indexes may be represented as decimal numbers in keys.

nil is returned on error. Use Parser for proper error handling.

Parser is faster for obtaining multiple fields from JSON.

func GetFloat64

func GetFloat64(data []byte, keys ...string) float64

GetFloat64 returns float64 value for the field identified by keys path in JSON data.

Array indexes may be represented as decimal numbers in keys.

0 is returned on error. Use Parser for proper error handling.

Parser is faster for obtaining multiple fields from JSON.

func GetInt

func GetInt(data []byte, keys ...string) int

GetInt returns int value for the field identified by keys path in JSON data.

Array indexes may be represented as decimal numbers in keys.

0 is returned on error. Use Parser for proper error handling.

Parser is faster for obtaining multiple fields from JSON.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
)

func main() {
	data := []byte(`{"foo": [233,true, {"bar": [2343]} ]}`)

	n1 := fastjson.GetInt(data, "foo", "0")
	fmt.Printf("data.foo[0] = %d\n", n1)

	n2 := fastjson.GetInt(data, "foo", "2", "bar", "0")
	fmt.Printf("data.foo[2].bar[0] = %d\n", n2)

}
Output:

data.foo[0] = 233
data.foo[2].bar[0] = 2343

func GetString

func GetString(data []byte, keys ...string) string

GetString returns string value for the field identified by keys path in JSON data.

Array indexes may be represented as decimal numbers in keys.

An empty string is returned on error. Use Parser for proper error handling.

Parser is faster for obtaining multiple fields from JSON.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
)

func main() {
	data := []byte(`{"foo":{"bar":[123,"baz"]}}`)

	s := fastjson.GetString(data, "foo", "bar", "1")
	fmt.Printf("data.foo.bar[1] = %s", s)

}
Output:

data.foo.bar[1] = baz

func Validate

func Validate(s string) error

Validate validates JSON s.

func ValidateBytes

func ValidateBytes(b []byte) error

ValidateBytes validates JSON b.

Types

type Arena

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

Arena may be used for fast creation and re-use of Values.

Typical Arena lifecycle:

  1. Construct Values via the Arena and Value.Set* calls.
  2. Marshal the constructed Values with Value.MarshalTo call.
  3. Reset all the constructed Values at once by Arena.Reset call.
  4. Go to 1 and re-use the Arena.

It is unsafe calling Arena methods from concurrent goroutines. Use per-goroutine Arenas or ArenaPool instead.

func (*Arena) NewArray

func (a *Arena) NewArray() *Value

NewArray returns new empty array value.

New entries may be added to the returned array via Set* calls.

The returned array is valid until Reset is called on a.

func (*Arena) NewFalse

func (a *Arena) NewFalse() *Value

NewFalse return false value.

func (*Arena) NewNull

func (a *Arena) NewNull() *Value

NewNull returns null value.

func (*Arena) NewNumberFloat64

func (a *Arena) NewNumberFloat64(f float64) *Value

NewNumberFloat64 returns new number value containing f.

The returned number is valid until Reset is called on a.

func (*Arena) NewNumberInt

func (a *Arena) NewNumberInt(n int) *Value

NewNumberInt returns new number value containing n.

The returned number is valid until Reset is called on a.

func (*Arena) NewNumberString

func (a *Arena) NewNumberString(s string) *Value

NewNumberString returns new number value containing s.

The returned number is valid until Reset is called on a.

func (*Arena) NewObject

func (a *Arena) NewObject() *Value

NewObject returns new empty object value.

New entries may be added to the returned object via Set call.

The returned object is valid until Reset is called on a.

func (*Arena) NewString

func (a *Arena) NewString(s string) *Value

NewString returns new string value containing s.

The returned string is valid until Reset is called on a.

func (*Arena) NewStringBytes

func (a *Arena) NewStringBytes(b []byte) *Value

NewStringBytes returns new string value containing b.

The returned string is valid until Reset is called on a.

func (*Arena) NewTrue

func (a *Arena) NewTrue() *Value

NewTrue returns true value.

func (*Arena) Reset

func (a *Arena) Reset()

Reset resets all the Values allocated by a.

Values previously allocated by a cannot be used after the Reset call.

type ArenaPool

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

ArenaPool may be used for pooling Arenas for similarly typed JSONs.

func (*ArenaPool) Get

func (ap *ArenaPool) Get() *Arena

Get returns an Arena from ap.

The Arena must be Put to ap after use.

func (*ArenaPool) Put

func (ap *ArenaPool) Put(a *Arena)

Put returns a to ap.

a and objects created by a cannot be used after a is put into ap.

type Object

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

Object represents JSON object.

Object cannot be used from concurrent goroutines. Use per-goroutine parsers or ParserPool instead.

func (*Object) Del

func (o *Object) Del(key string)

Del deletes the entry with the given key from o.

Example
package main

import (
	"fmt"
	"log"

	"gitee.com/quant1x/pkg/fastjson"
)

func main() {
	v := fastjson.MustParse(`{"foo": 123, "bar": [1,2], "baz": "xyz"}`)
	o, err := v.Object()
	if err != nil {
		log.Fatalf("cannot otain object: %s", err)
	}
	fmt.Printf("%s\n", o)

	o.Del("bar")
	fmt.Printf("%s\n", o)

	o.Del("foo")
	fmt.Printf("%s\n", o)

	o.Del("baz")
	fmt.Printf("%s\n", o)

}
Output:

{"foo":123,"bar":[1,2],"baz":"xyz"}
{"foo":123,"baz":"xyz"}
{"baz":"xyz"}
{}

func (*Object) Get

func (o *Object) Get(key string) *Value

Get returns the value for the given key in the o.

Returns nil if the value for the given key isn't found.

The returned value is valid until Parse is called on the Parser returned o.

func (*Object) Len

func (o *Object) Len() int

Len returns the number of items in the o.

func (*Object) MarshalTo

func (o *Object) MarshalTo(dst []byte) []byte

MarshalTo appends marshaled o to dst and returns the result.

func (*Object) Set

func (o *Object) Set(key string, value *Value)

Set sets (key, value) entry in the o.

The value must be unchanged during o lifetime.

func (*Object) String

func (o *Object) String() string

String returns string representation for the o.

This function is for debugging purposes only. It isn't optimized for speed. See MarshalTo instead.

func (*Object) Visit

func (o *Object) Visit(f func(key []byte, v *Value))

Visit calls f for each item in the o in the original order of the parsed JSON.

f cannot hold key and/or v after returning.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
	"log"
)

func main() {
	s := `{
		"obj": { "foo": 1234 },
		"arr": [ 23,4, "bar" ],
		"str": "foobar"
	}`

	var p fastjson.Parser
	v, err := p.Parse(s)
	if err != nil {
		log.Fatalf("cannot parse json: %s", err)
	}
	o, err := v.Object()
	if err != nil {
		log.Fatalf("cannot obtain object from json value: %s", err)
	}

	o.Visit(func(k []byte, v *fastjson.Value) {
		switch string(k) {
		case "obj":
			fmt.Printf("object %s\n", v)
		case "arr":
			fmt.Printf("array %s\n", v)
		case "str":
			fmt.Printf("string %s\n", v)
		}
	})

}
Output:

object {"foo":1234}
array [23,4,"bar"]
string "foobar"

type Parser

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

Parser parses JSON.

Parser may be re-used for subsequent parsing.

Parser cannot be used from concurrent goroutines. Use per-goroutine parsers or ParserPool instead.

func (*Parser) Parse

func (p *Parser) Parse(s string) (*Value, error)

Parse parses s containing JSON.

The returned value is valid until the next call to Parse*.

Use Scanner if a stream of JSON values must be parsed.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
	"log"
)

func main() {
	var p fastjson.Parser
	v, err := p.Parse(`{"foo":"bar", "baz": 123}`)
	if err != nil {
		log.Fatalf("cannot parse json: %s", err)
	}

	fmt.Printf("foo=%s, baz=%d", v.GetStringBytes("foo"), v.GetInt("baz"))

}
Output:

foo=bar, baz=123
Example (Reuse)
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
	"log"
	"strconv"
)

func main() {
	var p fastjson.Parser

	// p may be re-used for parsing multiple json strings.
	// This improves parsing speed by reducing the number
	// of memory allocations.
	//
	// Parse call invalidates all the objects previously obtained from p,
	// so don't hold these objects after parsing the next json.

	for i := 0; i < 3; i++ {
		s := fmt.Sprintf(`["foo_%d","bar_%d","%d"]`, i, i, i)
		v, err := p.Parse(s)
		if err != nil {
			log.Fatalf("cannot parse json: %s", err)
		}
		key := strconv.Itoa(i)
		fmt.Printf("a[%d]=%s\n", i, v.GetStringBytes(key))
	}

}
Output:

a[0]=foo_0
a[1]=bar_1
a[2]=2

func (*Parser) ParseBytes

func (p *Parser) ParseBytes(b []byte) (*Value, error)

ParseBytes parses b containing JSON.

The returned Value is valid until the next call to Parse*.

Use Scanner if a stream of JSON values must be parsed.

type ParserPool

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

ParserPool may be used for pooling Parsers for similarly typed JSONs.

func (*ParserPool) Get

func (pp *ParserPool) Get() *Parser

Get returns a Parser from pp.

The Parser must be Put to pp after use.

func (*ParserPool) Put

func (pp *ParserPool) Put(p *Parser)

Put returns p to pp.

p and objects recursively returned from p cannot be used after p is put into pp.

type Scanner

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

Scanner scans a series of JSON values. Values may be delimited by whitespace.

Scanner may parse JSON lines ( http://jsonlines.org/ ).

Scanner may be re-used for subsequent parsing.

Scanner cannot be used from concurrent goroutines.

Use Parser for parsing only a single JSON value.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
	"log"
)

func main() {
	var sc fastjson.Scanner

	sc.Init(`   {"foo":  "bar"  }[  ]
		12345"xyz" true false null    `)

	for sc.Next() {
		fmt.Printf("%s\n", sc.Value())
	}
	if err := sc.Error(); err != nil {
		log.Fatalf("unexpected error: %s", err)
	}

}
Output:

{"foo":"bar"}
[]
12345
"xyz"
true
false
null
Example (Reuse)
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
	"log"
)

func main() {
	var sc fastjson.Scanner

	// The sc may be re-used in order to reduce the number
	// of memory allocations.
	for i := 0; i < 3; i++ {
		s := fmt.Sprintf(`[%d] "%d"`, i, i)
		sc.Init(s)
		for sc.Next() {
			fmt.Printf("%s,", sc.Value())
		}
		if err := sc.Error(); err != nil {
			log.Fatalf("unexpected error: %s", err)
		}
		fmt.Printf("\n")
	}

}
Output:

[0],"0",
[1],"1",
[2],"2",

func (*Scanner) Error

func (sc *Scanner) Error() error

Error returns the last error.

func (*Scanner) Init

func (sc *Scanner) Init(s string)

Init initializes sc with the given s.

s may contain multiple JSON values, which may be delimited by whitespace.

func (*Scanner) InitBytes

func (sc *Scanner) InitBytes(b []byte)

InitBytes initializes sc with the given b.

b may contain multiple JSON values, which may be delimited by whitespace.

func (*Scanner) Next

func (sc *Scanner) Next() bool

Next parses the next JSON value from s passed to Init.

Returns true on success. The parsed value is available via Value call.

Returns false either on error or on the end of s. Call Error in order to determine the cause of the returned false.

func (*Scanner) Value

func (sc *Scanner) Value() *Value

Value returns the last parsed value.

The value is valid until the Next call.

type Type

type Type int

Type represents JSON type.

const (
	// TypeNull is JSON null.
	TypeNull Type = 0

	// TypeObject is JSON object type.
	TypeObject Type = 1

	// TypeArray is JSON array type.
	TypeArray Type = 2

	// TypeString is JSON string type.
	TypeString Type = 3

	// TypeNumber is JSON number type.
	TypeNumber Type = 4

	// TypeTrue is JSON true.
	TypeTrue Type = 5

	// TypeFalse is JSON false.
	TypeFalse Type = 6
)

func (Type) String

func (t Type) String() string

String returns string representation of t.

type Value

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

Value represents any JSON value.

Call Type in order to determine the actual type of the JSON value.

Value cannot be used from concurrent goroutines. Use per-goroutine parsers or ParserPool instead.

func MustParse

func MustParse(s string) *Value

MustParse parses json string s.

The function panics if s cannot be parsed. The function is slower than the Parser.Parse for re-used Parser.

func MustParseBytes

func MustParseBytes(b []byte) *Value

MustParseBytes parses b containing json.

The function panics if b cannot be parsed. The function is slower than the Parser.ParseBytes for re-used Parser.

func Parse

func Parse(s string) (*Value, error)

Parse parses json string s.

The function is slower than the Parser.Parse for re-used Parser.

func ParseBytes

func ParseBytes(b []byte) (*Value, error)

ParseBytes parses b containing json.

The function is slower than the Parser.ParseBytes for re-used Parser.

func (*Value) Array

func (v *Value) Array() ([]*Value, error)

Array returns the underlying JSON array for the v.

The returned array is valid until Parse is called on the Parser returned v.

Use GetArray if you don't need error handling.

func (*Value) Bool

func (v *Value) Bool() (bool, error)

Bool returns the underlying JSON bool for the v.

Use GetBool if you don't need error handling.

func (*Value) Del

func (v *Value) Del(key string)

Del deletes the entry with the given key from array or object v.

Example
package main

import (
	"fmt"

	"gitee.com/quant1x/pkg/fastjson"
)

func main() {
	v := fastjson.MustParse(`{"foo": 123, "bar": [1,2], "baz": "xyz"}`)
	fmt.Printf("%s\n", v)

	v.Del("foo")
	fmt.Printf("%s\n", v)

	v.Get("bar").Del("0")
	fmt.Printf("%s\n", v)

}
Output:

{"foo":123,"bar":[1,2],"baz":"xyz"}
{"bar":[1,2],"baz":"xyz"}
{"bar":[2],"baz":"xyz"}

func (*Value) Exists

func (v *Value) Exists(keys ...string) bool

Exists returns true if the field exists for the given keys path.

Array indexes may be represented as decimal numbers in keys.

func (*Value) Float64

func (v *Value) Float64() (float64, error)

Float64 returns the underlying JSON number for the v.

Use GetFloat64 if you don't need error handling.

func (*Value) Get

func (v *Value) Get(keys ...string) *Value

Get returns value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

nil is returned for non-existing keys path.

The returned value is valid until Parse is called on the Parser returned v.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
	"log"
)

func main() {
	s := `{"foo":[{"bar":{"baz":123,"x":"434"},"y":[]},[null, false]],"qwe":true}`
	var p fastjson.Parser
	v, err := p.Parse(s)
	if err != nil {
		log.Fatalf("cannot parse json: %s", err)
	}

	vv := v.Get("foo", "0", "bar", "x")
	fmt.Printf("foo[0].bar.x=%s\n", vv.GetStringBytes())

	vv = v.Get("qwe")
	fmt.Printf("qwe=%v\n", vv.GetBool())

	vv = v.Get("foo", "1")
	fmt.Printf("foo[1]=%s\n", vv)

	vv = v.Get("foo").Get("1").Get("1")
	fmt.Printf("foo[1][1]=%s\n", vv)

	// non-existing key
	vv = v.Get("foo").Get("bar").Get("baz", "1234")
	fmt.Printf("foo.bar.baz[1234]=%v\n", vv)

}
Output:

foo[0].bar.x=434
qwe=true
foo[1]=[null,false]
foo[1][1]=false
foo.bar.baz[1234]=<nil>

func (*Value) GetArray

func (v *Value) GetArray(keys ...string) []*Value

GetArray returns array value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

nil is returned for non-existing keys path or for invalid value type.

The returned array is valid until Parse is called on the Parser returned v.

func (*Value) GetBool

func (v *Value) GetBool(keys ...string) bool

GetBool returns bool value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

false is returned for non-existing keys path or for invalid value type.

func (*Value) GetFloat64

func (v *Value) GetFloat64(keys ...string) float64

GetFloat64 returns float64 value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

0 is returned for non-existing keys path or for invalid value type.

func (*Value) GetInt

func (v *Value) GetInt(keys ...string) int

GetInt returns int value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

0 is returned for non-existing keys path or for invalid value type.

func (*Value) GetInt64

func (v *Value) GetInt64(keys ...string) int64

GetInt64 returns int64 value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

0 is returned for non-existing keys path or for invalid value type.

func (*Value) GetObject

func (v *Value) GetObject(keys ...string) *Object

GetObject returns object value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

nil is returned for non-existing keys path or for invalid value type.

The returned object is valid until Parse is called on the Parser returned v.

func (*Value) GetString added in v0.2.1

func (v *Value) GetString(key string) string

func (*Value) GetStringBytes

func (v *Value) GetStringBytes(keys ...string) []byte

GetStringBytes returns string value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

nil is returned for non-existing keys path or for invalid value type.

The returned string is valid until Parse is called on the Parser returned v.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
	"log"
)

func main() {
	s := `[
		{"foo": "bar"},
		[123, "baz"]
	]`

	var p fastjson.Parser
	v, err := p.Parse(s)
	if err != nil {
		log.Fatalf("cannot parse json: %s", err)
	}
	fmt.Printf("v[0].foo = %q\n", v.GetStringBytes("0", "foo"))
	fmt.Printf("v[1][1] = %q\n", v.GetStringBytes("1", "1"))
	fmt.Printf("v[1][0] = %q\n", v.GetStringBytes("1", "0"))
	fmt.Printf("v.foo.bar.baz = %q\n", v.GetStringBytes("foo", "bar", "baz"))

}
Output:

v[0].foo = "bar"
v[1][1] = "baz"
v[1][0] = ""
v.foo.bar.baz = ""

func (*Value) GetUint

func (v *Value) GetUint(keys ...string) uint

GetUint returns uint value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

0 is returned for non-existing keys path or for invalid value type.

func (*Value) GetUint64

func (v *Value) GetUint64(keys ...string) uint64

GetUint64 returns uint64 value by the given keys path.

Array indexes may be represented as decimal numbers in keys.

0 is returned for non-existing keys path or for invalid value type.

func (*Value) Int

func (v *Value) Int() (int, error)

Int returns the underlying JSON int for the v.

Use GetInt if you don't need error handling.

func (*Value) Int64

func (v *Value) Int64() (int64, error)

Int64 returns the underlying JSON int64 for the v.

Use GetInt64 if you don't need error handling.

func (*Value) MarshalTo

func (v *Value) MarshalTo(dst []byte) []byte

MarshalTo appends marshaled v to dst and returns the result.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
	"log"
)

func main() {
	s := `{
		"name": "John",
		"items": [
			{
				"key": "foo",
				"value": 123.456,
				"arr": [1, "foo"]
			},
			{
				"key": "bar",
				"field": [3, 4, 5]
			}
		]
	}`
	var p fastjson.Parser
	v, err := p.Parse(s)
	if err != nil {
		log.Fatalf("cannot parse json: %s", err)
	}

	// Marshal items.0 into newly allocated buffer.
	buf := v.Get("items", "0").MarshalTo(nil)
	fmt.Printf("items.0 = %s\n", buf)

	// Re-use buf for marshaling items.1.
	buf = v.Get("items", "1").MarshalTo(buf[:0])
	fmt.Printf("items.1 = %s\n", buf)

}
Output:

items.0 = {"key":"foo","value":123.456,"arr":[1,"foo"]}
items.1 = {"key":"bar","field":[3,4,5]}

func (*Value) Object

func (v *Value) Object() (*Object, error)

Object returns the underlying JSON object for the v.

The returned object is valid until Parse is called on the Parser returned v.

Use GetObject if you don't need error handling.

func (*Value) Set

func (v *Value) Set(key string, value *Value)

Set sets (key, value) entry in the array or object v.

The value must be unchanged during v lifetime.

Example
package main

import (
	"fmt"

	"gitee.com/quant1x/pkg/fastjson"
)

func main() {
	v := fastjson.MustParse(`{"foo":1,"bar":[2,3]}`)

	// Replace `foo` value with "xyz"
	v.Set("foo", fastjson.MustParse(`"xyz"`))
	// Add "newv":123
	v.Set("newv", fastjson.MustParse(`123`))
	fmt.Printf("%s\n", v)

	// Replace `bar.1` with {"x":"y"}
	v.Get("bar").Set("1", fastjson.MustParse(`{"x":"y"}`))
	// Add `bar.3="qwe"
	v.Get("bar").Set("3", fastjson.MustParse(`"qwe"`))
	fmt.Printf("%s\n", v)

}
Output:

{"foo":"xyz","bar":[2,3],"newv":123}
{"foo":"xyz","bar":[2,{"x":"y"},null,"qwe"],"newv":123}

func (*Value) SetArrayItem

func (v *Value) SetArrayItem(idx int, value *Value)

SetArrayItem sets the value in the array v at idx position.

The value must be unchanged during v lifetime.

func (*Value) String

func (v *Value) String() string

String returns string representation of the v.

The function is for debugging purposes only. It isn't optimized for speed. See MarshalTo instead.

Don't confuse this function with StringBytes, which must be called for obtaining the underlying JSON string for the v.

func (*Value) StringBytes

func (v *Value) StringBytes() ([]byte, error)

StringBytes returns the underlying JSON string for the v.

The returned string is valid until Parse is called on the Parser returned v.

Use GetStringBytes if you don't need error handling.

func (*Value) Type

func (v *Value) Type() Type

Type returns the type of the v.

Example
package main

import (
	"fmt"
	"gitee.com/quant1x/pkg/fastjson"
	"log"
)

func main() {
	s := `{
		"object": {},
		"array": [],
		"string": "foobar",
		"number": 123.456,
		"true": true,
		"false": false,
		"null": null
	}`

	var p fastjson.Parser
	v, err := p.Parse(s)
	if err != nil {
		log.Fatalf("cannot parse json: %s", err)
	}

	fmt.Printf("%s\n", v.Get("object").Type())
	fmt.Printf("%s\n", v.Get("array").Type())
	fmt.Printf("%s\n", v.Get("string").Type())
	fmt.Printf("%s\n", v.Get("number").Type())
	fmt.Printf("%s\n", v.Get("true").Type())
	fmt.Printf("%s\n", v.Get("false").Type())
	fmt.Printf("%s\n", v.Get("null").Type())

}
Output:

object
array
string
number
true
false
null

func (*Value) Uint

func (v *Value) Uint() (uint, error)

Uint returns the underlying JSON uint for the v.

Use GetInt if you don't need error handling.

func (*Value) Uint64

func (v *Value) Uint64() (uint64, error)

Uint64 returns the underlying JSON uint64 for the v.

Use GetInt64 if you don't need error handling.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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