flatjson

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Jan 30, 2025 License: MIT Imports: 4 Imported by: 1

README

flatjson

Fast and dirty parsing of JSON! Decode only the parts you care about!

Why

This parser is very fast (or I mean it's not slow?) and allows you to only parse the things you care about. It also allows you to "visit" all the keys of a JSON entity recursively, in a single pass.

data := []byte(`{
    "hello":["world"],
    "bonjour": {"le": "monde"}
}`)

flatjson.ScanObject(data, 0, &flatjson.Callbacks{
    MaxDepth: 99,
    OnNumber: func(prefixes flatjson.Prefixes, val flatjson.Number) {
        // handle
    },
    OnString: func(prefixes flatjson.Prefixes, val flatjson.String) {
        // handle
    },
    OnBoolean: func(prefixes flatjson.Prefixes, val flatjson.Bool) {
        // handle
    },
    OnNull: func(prefixes flatjson.Prefixes, val flatjson.Null) {
        // handle
    },
})

Speed

In a dumb benchmark:

BenchmarkFlatJSON-12        	 1660015	       722.9 ns/op	 930.93 MB/s	      32 B/op	       2 allocs/op
BenchmarkEncodingJSON-12    	  594927	      2394 ns/op	 311.13 MB/s	     168 B/op	       3 allocs/op

About that name

This library used to support only what I called a "flat" subset of JSON. But now it supports all JSON, but you can still decide how "flat" you want to go. The flatter, the faster :).

Flat JSON is a subset of JSON where the only supported types are objects containing strings, numbers, booleans or null values. There can't be nested objects or arrays. The root element must be an object.

Documentation

Index

Examples

Constants

View Source
const (
	EntityTypeInvalid = iota
	EntityTypeString
	EntityTypeObject
	EntityTypeArray
	EntityTypeNumber
	EntityTypeBooleanTrue
	EntityTypeBooleanFalse
	EntityTypeNull
)

Variables

This section is empty.

Functions

func ScanNumber

func ScanNumber(data []byte, i int) (float64, int, error)

ScanNumber reads a JSON number value from data and advances i one past the last number component it found. It does not deal with whitespace.

Types

type Bool

type Bool struct {
	Name  Prefix
	Value bool
}

type BooleanDec

type BooleanDec func(prefixes Prefixes, val Bool)

type Callbacks

type Callbacks struct {
	MaxDepth int

	OnNumber  NumberDec
	OnString  StringDec
	OnBoolean BooleanDec
	OnNull    NullDec

	OnRaw func(prefixes Prefixes, name Prefix, value Pos)
	// contains filtered or unexported fields
}

type EntityType

type EntityType uint8

func GuessNextEntityType

func GuessNextEntityType(data []byte, i int) EntityType

type Null

type Null struct{ Name Prefix }

type NullDec

type NullDec func(prefixes Prefixes, val Null)

type Number

type Number struct {
	Name  Prefix
	Value float64
}

type NumberDec

type NumberDec func(prefixes Prefixes, val Number)

type Pos

type Pos struct {
	From int
	To   int
}

func ScanObject

func ScanObject(data []byte, from int, cb *Callbacks) (pos Pos, found bool, err error)

ScanObject according to the spec at http://www.json.org/ but ignoring nested objects and arrays

Example
package main

import (
	"fmt"

	"github.com/calebglawson/flatjson"
)

func main() {
	data := []byte(`{
		"hello":["world"],
		"bonjour": {"le": "monde"}
	}`)

	_, _, _ = flatjson.ScanObject(data, 0, &flatjson.Callbacks{
		MaxDepth: 99,
		OnNumber: func(prefixes flatjson.Prefixes, val flatjson.Number) {
			fmt.Printf("path=%s\n", prefixes.AsString(data))
			if val.Name.IsObjectKey() {
				fmt.Printf("key=%s\n", val.Name.String(data))
			} else {
				fmt.Printf("index=%d\n", val.Name.Index())
			}
			fmt.Printf("value=%f\n", val.Value)
		},
		OnString: func(prefixes flatjson.Prefixes, val flatjson.String) {
			fmt.Printf("path=%s\n", prefixes.AsString(data))
			if val.Name.IsObjectKey() {
				fmt.Printf("key=%s\n", val.Name.String(data))
			} else {
				fmt.Printf("index=%d\n", val.Name.Index())
			}
			fmt.Printf("value=%q\n", val.Value.String(data))
		},
		OnBoolean: func(prefixes flatjson.Prefixes, val flatjson.Bool) {
			fmt.Printf("path=%s\n", prefixes.AsString(data))
			if val.Name.IsObjectKey() {
				fmt.Printf("key=%s\n", val.Name.String(data))
			} else {
				fmt.Printf("index=%d\n", val.Name.Index())
			}
			fmt.Printf("value=%v\n", val.Value)
		},
		OnNull: func(prefixes flatjson.Prefixes, val flatjson.Null) {
			fmt.Printf("path=%s\n", prefixes.AsString(data))
			if val.Name.IsObjectKey() {
				fmt.Printf("key=%s\n", val.Name.String(data))
			} else {
				fmt.Printf("index=%d\n", val.Name.Index())
			}
			fmt.Printf("NULL!")
		},
	})

}
Output:
path=hello
index=0
value="\"world\""
path=bonjour
key="le"
value="\"monde\""

func (Pos) Bytes

func (p Pos) Bytes(data []byte) []byte

func (Pos) String

func (p Pos) String(data []byte) string

type Prefix

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

func (Prefix) Bytes

func (pfx Prefix) Bytes(data []byte) []byte

func (Prefix) Index

func (pfx Prefix) Index() int

func (Prefix) IsArrayIndex

func (pfx Prefix) IsArrayIndex() bool

func (Prefix) IsObjectKey

func (pfx Prefix) IsObjectKey() bool

func (Prefix) String

func (pfx Prefix) String(data []byte) string

type Prefixes

type Prefixes []Prefix

func (Prefixes) AsString

func (pfxs Prefixes) AsString(data []byte) string

type String

type String struct {
	Name  Prefix
	Value Pos
}

type StringDec

type StringDec func(prefixes Prefixes, val String)

type SyntaxError

type SyntaxError struct {
	Offset  int
	Message string

	SubErr *SyntaxError
}

func (*SyntaxError) Error

func (s *SyntaxError) Error() string

Jump to

Keyboard shortcuts

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