jin

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Mar 2, 2024 License: MIT Imports: 9 Imported by: 1

README

CircleCIGo Report Card License GoDoc

Welcome To JIN

"Your wish is my command"

Fast and Easy Way to Deal With JSON

Jin is a comprehensive JSON manipulation tool bundle. All functions tested with random data with help of Node.js. All test-path and test-value creation automated with Node.js.

Jin provides parse, interpret, build and format tools for JSON. Third-party packages only used for the benchmark. No dependency need for core functions.

We make some benchmark with other packages like Jin.

    github.com/buger/jsonparser
    github.com/valyala/fastjson
    github.com/json-iterator/go
    github.com/tidwall/gjson
    github.com/tidwall/sjson

In Result, Jin is the fastest (op/ns) and more memory friendly then others (B/op).

For more information please take a look at BENCHMARK section below.


What is New?
08.10.2021

Store New! store function. store function can set or override a value like a real JSON object.

04.01.2021

JO (JsonObject) introduced!! Actually that is a fancy word for []byte type

You can use all interpreter functions with JO. just initialize and go.

Get() Example

	// instead of repeating []byte for all functions.
	// initialize
	jsonObject := jin.New(json)
	// and go
	serial, err := jsonObject.GetString("info", "serial")
	if err != nil {
		return err
	}
	pooling, err := jsonObject.GetFloat("info", "polling_time")
	if err != nil {
		return err
	}

	// old declaration
	serial, err := jin.GetString(json, "info", "serial")
	if err != nil {
		return err
	}
	pooling, err := jin.GetFloat(json, "info", "polling_time")
	if err != nil {
		return err
	}

Set() Example

	// instead of repeating []byte for all functions.
	// initialize
	jsonObject := jin.New(json)
	// and go
	err := jsonObject.SetString("at-28C02", "info", "serial")
	if err != nil {
		return err
	}

	// old declaration
	json, err := jin.SetString(json, "at-28C02", "info", "serial")
	if err != nil {
		return err
	}

06.04.2020

7 new functions tested and added to package. Examples in GoDoc

  • GetMap() get objects as map[string]string structure with key values pairs
  • GetAll() get only specific keys values
  • GetAllMap() get only specific keys with map[string]stringstructure
  • GetKeys() get objects keys as string array
  • GetValues() get objects values as string array
  • GetKeysValues() get objects keys and values with separate string arrays
  • Length() get length of JSON array.

Installation
	go get github.com/ecoshub/jin

And you are good to go. Import and start using.


Documentation

There is a detailed documentation in GoDoc with lots of examples.


QUICK START
Parser vs Interpreter

Major difference between parsing and interpreting is parser has to read all data before answer your needs. On the other hand interpreter reads up to find the data you need.

With parser, once the parse is complete you can access any data with no time. But there is a time cost to parse all data and this cost can increase as data content grows.

If you need to access all keys of a JSON then, we are simply recommend you to use Parser. But if you need to access some keys of a JSON then we strongly recommend you to use Interpreter, it will be much faster and much more memory-friendly than parser.

Interpreter

Interpreter is core element of this package, no need to create an Interpreter type, just call which function you want.

First let's look at general function parameters.


	// All interpreter functions need one JSON as byte slice.
	json := []byte(`{"git":"ecoshub","repo":{"id":233809925,"name":["eco","jin"]}}`)

	// And most of them needs a path value for navigate.
	// Path value determines which part to navigate.
	// In this example we want to access 'jin' value.
	// So path must be 'repo' (object) -> 'name' (array) -> '1' (second element)
	path := []string{"repo", "name", "1"}

We are gonna use Get() function to access the value of path has pointed. In this case 'jin'.


	value, err := jin.Get(json, path...)
	if err != nil {
		log.Println(err)
		return
	}
	// the Get() functions return type is []byte
	// To understand its value,
	// first we have to convert it to string.
	fmt.Println(string(value))
	// Output: jin

Path value can consist hard coded values.


	value, err := jin.Get(json, "repo", "name", "1")
	if err != nil {
		log.Println(err)
		return
	}

	fmt.Println(string(value))
	//String Output: jin

Get() function return type is []byte but all other variations of return types are implemented with different functions.

For example. If you need "value" as string use GetString().


	value, err := jin.GetString(json, "repo", "name", "0")
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(string(value))
	//Output: eco

For example. If you need "value" as string use GetString().


	value, err := jin.GetString(json, "repo", "name", "0")
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(string(value))
	//Output: eco


Parser

Parser is another alternative for JSON manipulation.

We recommend to use this structure when you need to access all or most of the keys in the JSON.

Parser constructor need only one parameter.


	// Parser constructor function jin.Parse() need one JSON as []byte.
	json := []byte(`
	{
		"title": "LICENSE",
		"repo": {
			"id": 233809925,
			"name": "ecoshub/jin",
			"url": "https://api.github.com/repos/ecoshub/jin"
			}
	}`)

We can parse it with Parse() function.


	prs, err := jin.Parse(json)
	if err != nil {
		log.Println(err)
		return
	}

Let's look at Parser.Get()


	value, err := prs.Get("repo", "url")
	if err != nil {
		log.Println(err)
		return
	}

	fmt.Println(string(value))
	//Output: https://api.github.com/repos/ecoshub/jin

About path value look above.

There is all return type variations of Parser.Get() function like Interpreter.

For return string use Parser.GetString() like this,


	value, err := prs.GetString("repo", "name")
	if err != nil {
		log.Println(err)
		return
	}
	fmt.Println(value)
	//String Output: ecoshub/jin

All functions has own example provided in GoDoc.

Other usefull functions of Jin.

-Add(), AddKeyValue(), Set(), SetKey() Delete(), Insert(), IterateArray(), IterateKeyValue() Tree().


Iteration Tools

Iteration tools provide functions for access each key-value pair or each value of an array

Let's look at IterateArray() function.

	// JSON that we want to access.
	json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"]}`)

	// IterateArray() uses a callback function to return elements.
	err := jin.IterateArray(json, func(value []byte) (bool, error) {

		// printing current element as string.
		fmt.Println(string(value))

		// this return is some kind of control mechanism for escape from iteration any time.
		// true means keep iterate. false means stop the iteration.
		return true, nil
	// last parameter is path. Its currently pointing at "language" array.
	}, "languages")

	// standard error definition
	if err != nil {
		log.Println(err)
		return
	}

	// Output: go
	// java
	// python
	// C
	// Cpp

Another useful function is IterateKeyValue()check for example in GoDoc.


Other Tools
Formatting

There are two formatting functions. Flatten() and Indent().

Indent() is adds indentation to JSON for nicer visualization and Flatten() removes this indentation.

Examples in GoDoc.

Control Functions

Control functions are simple and easy way to check value types of any path.

For example. IsArray().


	json := []byte(`{"repo":{"name":"ecoshub/jin"},"others":["jin","penman"]}`)

	result, _ := jin.IsArray(json, "repo")
	fmt.Println(result)
	// Output: false

	result, _ = jin.IsArray(json, "others")
	fmt.Println(result)
	// Output: true


Or you can use GetType().


	json := []byte(`{"git":"ecoshub","repo":["jin","wsftp","penman"]}`)

	result, _ := jin.GetType(json, "repo")
	fmt.Println(result)
	// Output: array

JSON Build Tools

There are lots of JSON build functions in this package and all of them has its own examples.

We just want to mention a couple of them.

Scheme is simple and powerful tool for create JSON schemes.


	// MakeScheme need keys for construct a JSON scheme.
	person := MakeScheme("name", "lastname", "age")

	// now we can instantiate a JSON with values.
	eco := person.MakeJson("eco", "hub", "28")
	// {"name":"eco","lastname":"hub","age":28}

	koko := person.MakeJson("koko", "Bloom", "42")
	//{"name":"koko","lastname":"Bloom","age":42}

MakeJson(), MakeArray() functions and other variations are easy to use functions. Go and take a look. GoDoc.


Testing

Testing is very important thing for this type of packages and it shows how reliable it is.

For that reasons we use Node.js for unit testing.

Lets look at folder arrangement and working principle.

  • test/ folder:

    • test-json.json, this is a temporary file for testing. all other test-cases copying here with this name so they can process by test-case-creator.js.

    • test-case-creator.js is core path & value creation mechanism. When it executed with executeNode() function. It reads the test-json.json file and generates the paths and values from this files content. With command line arguments it can generate different paths and values. As a result, two files are created with this process. the first of these files is test-json-paths.json and the second is test-json-values.json

    • test-json-paths.json has all the path values.

    • test-json-values.json has all the values that corresponding to path values.

  • tests/ folder

    • All files in this folder is a test-case. But it doesn't mean that you can't change anything, on the contrary, all test-cases are creating automatically based on this folder content. You can add or remove any .json file that you want.

    • All GO side test-case automation functions are in core_test.go file.

This package developed with Node.js v13.7.0. please make sure that your machine has a valid version of Node.js before testing.

All functions and methods are tested with complicated randomly genereted .json files.

Like this,


	{
		"g;}\\=LUG[5pwAizS!lfkdRULF=": true,
		"gL1GG'S+-U~#fUz^R^=#genWFVGA$O": {
			"Nmg}xK&V5Z": -1787764711,
			"=B7a(KoF%m5rqG#En}dl\"y`117)WC&w~": -572664066,
			"Dj_{6evoMr&< 4m+1u{W!'zf;cl": ":mqp<s6('&??yG#)qpMs=H?",
			",Qx_5V(ceN)%0d-h.\"\"0v}8fqG-zgEBz;!C{zHZ#9Hfg%no*": false,
			"l&d>": true
		},
		"jhww/SRq?,Y\"5O1'{": "]\"4s{WH]b9aR+[$-'PQm8WW:B",
		":e": "Lu9(>9IbrLyx60E;9R]NHml@A~} QHgAUR5$TUCm&z,]d\">",
		"e&Kk^`rz`T!EZopgIo\\5)GT'MkSCf]2<{dt+C_H": 599287421.0854483
	}

Most of JSON packages not even run properly with this kind of JSON streams. We did't see such packages as competitors to ourselves. And that's because we didn't even bother to benchmark against them.


Benchmark

Benchmark results.

  • Benchmark prefix removed from function names for make room to results.

  • Benchmark between 'buger/jsonparser' and 'ecoshub/jin' use the same payload (JSON test-cases) that 'buger/jsonparser' package use for benchmark it self.

    github.com/ecoshub/jin -> Jin

    github.com/buger/jsonparser -> Jsonparser

    github.com/valyala/fastjson -> Fastjson

    github.com/json-iterator/go -> Jsoniterator

    github.com/tidwall/gjson -> gjson

    github.com/tidwall/sjson -> sjon


	goos: linux
	goarch: amd64
	pkg: jin/benchmark

	// Get function (interpert)
	JsoniteratorGetSmall-8             2862 ns/op          597 B/op          40 allocs/op
	GjsonGetSmall-8                     921 ns/op           64 B/op           3 allocs/op
	JsonparserGetSmall-8                787 ns/op            0 B/op           0 allocs/op
	JinGetSmall-8                       729 ns/op            0 B/op           0 allocs/op
	GjsonGetMedium-8                   7084 ns/op          152 B/op           4 allocs/op
	JsonparserGetMedium-8              7329 ns/op            0 B/op           0 allocs/op
	JinGetMedium-8                     5624 ns/op            0 B/op           0 allocs/op
	GjsonrGetLarge-8                 119925 ns/op        28672 B/op           2 allocs/op
	JsonparserGetLarge-8              65725 ns/op            0 B/op           0 allocs/op
	JinGetLarge-8                     61516 ns/op            0 B/op           0 allocs/op

	// Array iteration function (interpert)
	IterateArrayGetGjson-8            21966 ns/op         8192 B/op           1 allocs/op
	IterateArrayGetJsonparser-8       11814 ns/op            0 B/op           0 allocs/op
	IterateArrayGetJin-8              11639 ns/op            0 B/op           0 allocs/op
	IterateObjectGetGjson-8           11329 ns/op         2304 B/op           1 allocs/op
	IterateObjectGetJsonparser-8       6100 ns/op            0 B/op           0 allocs/op
	IterateObjectGetJin-8              4551 ns/op            0 B/op           0 allocs/op

	// Set function (interpert)
	SJonSetSmall-8                     2126 ns/op         1664 B/op           9 allocs/op
	JsonParserSetSmall-8               1261 ns/op          704 B/op           4 allocs/op
	JinSetSmall-8                      1244 ns/op          704 B/op           4 allocs/op
	SjsonSetMedium-8                  15412 ns/op        13008 B/op          11 allocs/op
	JsonParserSetMedium-8              6868 ns/op         6912 B/op           3 allocs/op
	JinSetMedium-8                     6169 ns/op         6912 B/op           3 allocs/op
	SjsonSetLarge-8                  257300 ns/op       136736 B/op          14 allocs/op
	JsonParserSetLarge-8             121874 ns/op       114688 B/op           4 allocs/op
	JinSetLarge-8                     86574 ns/op       114688 B/op           4 allocs/op

	// Delete function (interpert)
	JsonParserDeleteSmall-8            2015 ns/op          704 B/op           4 allocs/op
	JinDeleteSmall-8                   1198 ns/op          640 B/op           4 allocs/op
	JsonParserDeleteMedium-8          10321 ns/op         6912 B/op           3 allocs/op
	JinDeleteMedium-8                  5780 ns/op         6144 B/op           3 allocs/op
	JsonParserDeleteLarge-8          123737 ns/op       114688 B/op           4 allocs/op
	JinDeleteLarge-8                  87322 ns/op       114688 B/op           4 allocs/op

	// Get function (parse)
	FastjsonGetSmall-8                 2755 ns/op         3408 B/op          11 allocs/op
	JinParseGetSmall-8                 1981 ns/op         1252 B/op          28 allocs/op
	FastjsonGetMedium-8               14958 ns/op        17304 B/op          54 allocs/op
	JinParseGetMedium-8               14175 ns/op         8304 B/op         201 allocs/op
	FastjsonGetLarge-8               229188 ns/op       283200 B/op         540 allocs/op
	JinParseGetLarge-8               222246 ns/op       134704 B/op        2903 allocs/op

	// Set function (parse)
	FastjsonSetSmall-8                 3709 ns/op         3792 B/op          19 allocs/op
	JinParseSetSmall-8                 3265 ns/op         1968 B/op          36 allocs/op


Upcoming

We are currently working on,

  • Marshal() and Unmarshal() functions.

  • http.Request parser/interpreter

  • Builder functions for http.ResponseWriter


Contribute

If you want to contribute this work feel free to fork it.

We want to fill this section with contributors.

Documentation

Overview

Package jin

Copyright (c) 2020 eco.

License that can be found in the LICENSE file.

WELCOME TO JIN

"your wish is my command"

FAST AND EASY WAY TO DEAL WITH JSON

Jin is a comprehensive JSON manipulation tool bundle. All functions tested with random data with help of Node.js. All test-path and test-value creation automated with Node.js.

Jin provides parse, interpret, build and format tools for JSON. Third-party packages only used for the benchmark. No dependency need for core functions.

We make some benchmark with other packages like Jin.

github.com/buger/jsonparser
github.com/valyala/fastjson
github.com/json-iterator/    github.com/tidwall/gjson
github.com/tidwall/sjson

In Result, Jin is the fastest (op/ns) and more memory friendly then others (B/op).

For more information please take a look at BENCHMARK section below.

WHAT IS NEW?

7 new functions tested and added to package.

- GetMap() get objects as map[string]string structure with key values pairs

- GetAll() get only specific keys values

- GetAllMap() get only specific keys with map[string]stringstructure

- GetKeys() get objects keys as string array

- GetValues() get objects values as string array

- GetKeysValues() get objects keys and values with separate string arrays

- Length() get length of JSON array.

06.04.2020

INSTALLATION

go get github.com/ecoshub/jin

And you are good to go. Import and start using.

QUICK START

PARSER VS INTERPRETER

Major difference between parsing and interpreting is parser has to read all data before answer your needs. On the other hand interpreter reads up to find the data you need.

With parser, once the parse is complete you can access any data with no time. But there is a time cost to parse all data and this cost can increase as data content grows.

If you need to access all keys of a JSON then, we are simply recommend you to use Parser. But if you need to access some keys of a JSON then we strongly recommend you to use Interpreter, it will be much faster and much more memory-friendly than parser.

INTERPRETER

Interpreter is core element of this package, no need to create an Interpreter type, just call which function you want.

First let's look at general function parameters.

// All interpreter functions need one JSON as byte slice.
json := []byte({"git":"ecoshub","repo":{"id":233809925,"name":["eco","jin"]}})

// And most of them needs a path value for navigate.
// Path value determines which part to navigate.
// In this example we want to access 'jin' value.
// So path must be 'repo' (object) -> 'name' (array) -> '1' (second element)
path := []string{"repo", "name", "1"}

We are gonna use Get() function to access the value of path has pointed. In this case 'jin'.

value, err := jin.Get(json, path...)
if err != nil {
	log.Println(err)
	return
}
// the Get() functions return type is []byte
// To understand its value,
// first we have to convert it to string.
fmt.Println(string(value))
// Output: jin

Path value can consist hard coded values.

value, err := jin.Get(json, "repo", "name", "1")
if err != nil {
	log.Println(err)
	return
}

fmt.Println(string(value))
//String Output: jin

Get() function return type is []byte but all other variations of return types are implemented with different functions.

For example. If you need "value" as string use GetString().

value, err := jin.GetString(json, "repo", "name", "0")
if err != nil {
	fmt.Println(err)
	return
}

fmt.Println(string(value))
//Output: eco

PARSER

Parser is another alternative for JSON manipulation.

We recommend to use this structure when you need to access all or most of the keys in the JSON.

Parser constructor need only one parameter.

// Parser constructor function jin.Parse() need one JSON as []byte.
json := []byte(
{
	"title": "LICENSE",
	"repo": {
		"id": 233809925,
		"name": "ecoshub/jin",
		"url": "https://api.github.com/repos/ecoshub/jin"
		}
})

We can parse it with Parse() function.

prs, err := jin.Parse(json)
if err != nil {
	log.Println(err)
	return
}

Let's look at Parser.Get()

value, err := prs.Get("repo", "url")
if err != nil {
	log.Println(err)
	return
}

fmt.Println(string(value))
//Output: https://api.github.com/repos/ecoshub/jin

About path value look above.

There is all return type variations of Parser.Get() function like Interpreter.

For return string use Parser.GetString() like this,

value, err := prs.GetString("repo", "name")
if err != nil {
	log.Println(err)
	return
}
fmt.Println(value)
//String Output: ecoshub/jin

Other usefull functions of Jin.

-Add(), AddKeyValue(), Set(), SetKey() Delete(), Insert(), IterateArray(), IterateKeyValue() Tree().

ITERATION TOOLS

Iteration tools provide functions for access each key-value pair or each value of an array

Let's look at IterateArray() function.

// JSON that we want to access.
json := []byte({"user":"eco","languages":["go","java","python","C","Cpp"]})

// IterateArray() uses a callback function to return elements.
err := jin.IterateArray(json, func(value []byte) bool {

	// printing current element as string.
	fmt.Println(string(value))

	// this return is some kind of control mechanism for escape from iteration any time.
	// true means keep iterate. false means stop the iteration.
	return true
// last parameter is path. Its currently pointing at "language" array.
}, "languages")

// standard error definition
if err != nil {
	log.Println(err)
	return
}

// Output: 	// java
// python
// C
// Cpp

OTHER TOOLS

FORMATTING

There are two formatting functions. Flatten() and Indent().

Indent() is adds indentation to JSON for nicer visualization and Flatten() removes this indentation.

CONTROL FUNCTIONS

Control functions are simple and easy way to check value types of any path.

For example. IsArray().

json := []byte({"repo":{"name":"ecoshub/jin"},"others":["jin","penman"]})

result, _ := jin.IsArray(json, "repo")
fmt.Println(result)
// Output: false

result, _ = jin.IsArray(json, "others")
fmt.Println(result)
// Output: true

Or you can use GetType().

json := []byte({"git":"ecoshub","repo":["jin","wsftp","penman"]})

result, _ := jin.GetType(json, "repo")
fmt.Println(result)
// Output: array

JSON BUILD TOOLS

There are lots of JSON build functions in this package and all of them has its own examples.

We just want to mention a couple of them.

Scheme is simple and powerful tool for create JSON schemes.

// MakeScheme need keys for construct a JSON scheme.
person := MakeScheme("name", "lastname", "age")

// now we can instantiate a JSON with values.
eco := person.MakeJson("eco", "hub", "28")
// {"name":"eco","lastname":"hub","age":28}

koko := person.MakeJson("koko", "Bloom", "42")
//{"name":"koko","lastname":"Bloom","age":42}

TESTING

Testing is very important thing for this type of packages and it shows how reliable it is.

For that reasons we use Node.js for unit testing.

Lets look at folder arrangement and working principle.

- test/ folder:

  • test-json.json, this is a temporary file for testing. all other test-cases copying here with this name so they can process by test-case-creator.js.

  • test-case-creator.js is core path & value creation mechanism. When it executed with executeNode() function. It reads the test-json.json file and generates the paths and values from this files content. With command line arguments it can generate different paths and values. As a result, two files are created with this process. the first of these files is test-json-paths.json and the second is test-json-values.json

  • test-json-paths.json has all the path values.

  • test-json-values.json has all the values that corresponding to path values.

- tests/ folder

  • All files in this folder is a test-case. But it doesn't mean that you can't change anything, on the contrary, all test-cases are creating automatically based on this folder content. You can add or remove any .json file that you want.

  • All GO side test-case automation functions are in core_test.go file.

This package developed with Node.js v13.7.0. please make sure that your machine has a valid version of Node.js before testing.

All functions and methods are tested with complicated randomly genereted .json files.

Like this,

{
	"g;}\\=LUG[5pwAizS!lfkdRULF=": true,
	"GL1GG'S+-U~UZ^R^=ENWFVGA$O": {
		"Nmg}xK&V5Z": -1787764711,
		"=B7A(KOF%M5RQGN}DL\"Y117)WC&W~": -572664066,
		"DJ_{6EVOMR&< 4M+1U{W!'ZF;CL": ":MQP<S6('&??YGQPMS=H?",
		",QX_5V(CEN)%0D-H.\"\"0V}8FQG-ZGEBZ;!C{ZHZHFG%NO": FALSE,
		"l&d>": true
	},
	"jhww/SRq?,Y\"5O1'{": "]\"4s{WH]b9aR+[$-'PQm8WW:B",
	":e": "Lu9(>9IbrLyx60E;9R]NHml@A~} QHgAUR5$TUCm&z,]d\">",
	"e&Kk^rzT!EZopgIo\\5)GT'MkSCf]2<{dt+C_H": 599287421.0854483
}

Most of JSON packages not even run properly with this kind of JSON streams. We did't see such packages as competitors to ourselves. And that's because we didn't even bother to benchmark against them.

BENCHMARK

Benchmark results.

- Benchmark prefix removed from function names for make room to results. - Benchmark between 'buger/jsonparser' and 'ecoshub/jin' use the same payload (JSON test-cases) that 'buger/jsonparser' package use for benchmark it self.

github.com/ecoshub/jin			-> Jin

github.com/buger/jsonparser	-> Jsonparser

github.com/valyala/fastjson	-> Fastjson

github.com/json-iterator/go	-> Jsoniterator

github.com/tidwall/gjson		-> gjson

github.com/tidwall/sjson		-> sjon

goos: linux
goarch: amd64
pkg: jin/benchmark

// Get function (interpert)
JsoniteratorGetSmall-8             2862 ns/op          597 B/op          40 allocs/op
GjsonGetSmall-8                     921 ns/op           64 B/op           3 allocs/op
JsonparserGetSmall-8                787 ns/op            0 B/op           0 allocs/op
JinGetSmall-8                       729 ns/op            0 B/op           0 allocs/op
GjsonGetMedium-8                   7084 ns/op          152 B/op           4 allocs/op
JsonparserGetMedium-8              7329 ns/op            0 B/op           0 allocs/op
JinGetMedium-8                     5624 ns/op            0 B/op           0 allocs/op
GjsonrGetLarge-8                 119925 ns/op        28672 B/op           2 allocs/op
JsonparserGetLarge-8              65725 ns/op            0 B/op           0 allocs/op
JinGetLarge-8                     61516 ns/op            0 B/op           0 allocs/op

// Array iteration function (interpert)
IterateArrayGetGjson-8            21966 ns/op         8192 B/op           1 allocs/op
IterateArrayGetJsonparser-8       11814 ns/op            0 B/op           0 allocs/op
IterateArrayGetJin-8              11639 ns/op            0 B/op           0 allocs/op
IterateObjectGetGjson-8           11329 ns/op         2304 B/op           1 allocs/op
IterateObjectGetJsonparser-8       6100 ns/op            0 B/op           0 allocs/op
IterateObjectGetJin-8              4551 ns/op            0 B/op           0 allocs/op

// Set function (interpert)
SJonSetSmall-8                     2126 ns/op         1664 B/op           9 allocs/op
JsonParserSetSmall-8               1261 ns/op          704 B/op           4 allocs/op
JinSetSmall-8                      1244 ns/op          704 B/op           4 allocs/op
SjsonSetMedium-8                  15412 ns/op        13008 B/op          11 allocs/op
JsonParserSetMedium-8              6868 ns/op         6912 B/op           3 allocs/op
JinSetMedium-8                     6169 ns/op         6912 B/op           3 allocs/op
SjsonSetLarge-8                  257300 ns/op       136736 B/op          14 allocs/op
JsonParserSetLarge-8             121874 ns/op       114688 B/op           4 allocs/op
JinSetLarge-8                     86574 ns/op       114688 B/op           4 allocs/op

// Delete function (interpert)
JsonParserDeleteSmall-8            2015 ns/op          704 B/op           4 allocs/op
JinDeleteSmall-8                   1198 ns/op          640 B/op           4 allocs/op
JsonParserDeleteMedium-8          10321 ns/op         6912 B/op           3 allocs/op
JinDeleteMedium-8                  5780 ns/op         6144 B/op           3 allocs/op
JsonParserDeleteLarge-8          123737 ns/op       114688 B/op           4 allocs/op
JinDeleteLarge-8                  87322 ns/op       114688 B/op           4 allocs/op

// Get function (parse)
FastjsonGetSmall-8                 2755 ns/op         3408 B/op          11 allocs/op
JinParseGetSmall-8                 1981 ns/op         1252 B/op          28 allocs/op
FastjsonGetMedium-8               14958 ns/op        17304 B/op          54 allocs/op
JinParseGetMedium-8               14175 ns/op         8304 B/op         201 allocs/op
FastjsonGetLarge-8               229188 ns/op       283200 B/op         540 allocs/op
JinParseGetLarge-8               222246 ns/op       134704 B/op        2903 allocs/op

// Set function (parse)
FastjsonSetSmall-8                 3709 ns/op         3792 B/op          19 allocs/op
JinParseSetSmall-8                 3265 ns/op         1968 B/op          36 allocs/op

UPCOMING

We are currently working on,

- Marshal() and Unmarshal() functions.

- http.Request parser/interpreter

- Builder functions for http.ResponseWriter

CONTRIBUTE

If you want to contribute this work feel free to fork it.

We want to fill this section with contributors.

Index

Examples

Constants

View Source
const (
	ErrCodeNullPath          int = 0
	ErrCodeEmptyArray        int = 2
	ErrCodeIndexExpected     int = 3
	ErrCodeObjectExpected    int = 5
	ErrCodeArrayExpected     int = 6
	ErrCodeIndexOutOfRange   int = 7
	ErrCodeKeyNotFound       int = 8
	ErrCodeBadJSON           int = 9
	ErrCodeKeyAlreadyExist   int = 11
	ErrCodeIntegerParse      int = 12
	ErrCodeFloatParse        int = 13
	ErrCodeBoolParse         int = 14
	ErrCodeStringArrayParse  int = 15
	ErrCodeIntegerArrayParse int = 16
	ErrCodeFloatArrayParse   int = 17
	ErrCodeBoolArrayParse    int = 18
	ErrCodeNullKey           int = 19
	ErrCodeEmpty             int = 20
)
View Source
const (
	TypeArray   string = "array"
	TypeObject  string = "object"
	TypeString  string = "string"
	TypeBoolean string = "boolean"
	TypeNull    string = "null"
	TypeNumber  string = "number"
)

Variables

This section is empty.

Functions

func Add

func Add(json []byte, value []byte, path ...string) ([]byte, error)

Add adds a value to an array. Path variable must point to an array, otherwise it will provide an error message.

Example
newValue := []byte(`"godoc.org/github.com/ecoshub"`)
json := []byte(`{"user":"eco","links":["github.com/ecoshub"]}`)

json, err := Add(json, newValue, "links")
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

{"user":"eco","links":["github.com/ecoshub","godoc.org/github.com/ecoshub"]}

func AddBool

func AddBool(json []byte, value bool, path ...string) ([]byte, error)

AddBool is a variation of Add() func. Type of new value must be an boolean.

func AddFloat

func AddFloat(json []byte, value float64, path ...string) ([]byte, error)

AddFloat is a variation of Add() func. Type of new value must be an float64.

func AddInt

func AddInt(json []byte, value int, path ...string) ([]byte, error)

AddInt is a variation of Add() func. Type of new value must be an integer.

func AddInt32 added in v1.0.1

func AddInt32(json []byte, value int32, path ...string) ([]byte, error)

AddInt32 is a variation of Add() func. Type of new value must be an integer.

func AddInt64 added in v1.0.1

func AddInt64(json []byte, value int64, path ...string) ([]byte, error)

AddInt64 is a variation of Add() func. Type of new value must be an integer.

func AddKeyValue

func AddKeyValue(json []byte, key string, value []byte, path ...string) ([]byte, error)

AddKeyValue adds a key-value pair to an object. Path variable must point to an object, otherwise it will provide an error message.

Example
newValue := []byte(`"go"`)
newKey := "language"
json := []byte(`{"user":"eco"}`)

json, err := AddKeyValue(json, newKey, newValue)
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

{"user":"eco","language":"go"}

func AddKeyValueBool

func AddKeyValueBool(json []byte, key string, value bool, path ...string) ([]byte, error)

AddKeyValueBool is a variation of AddKeyValue() func. Type of new value must be a boolean.

func AddKeyValueFloat

func AddKeyValueFloat(json []byte, key string, value float64, path ...string) ([]byte, error)

AddKeyValueFloat is a variation of AddKeyValue() func. Type of new value must be a float64.

func AddKeyValueInt

func AddKeyValueInt(json []byte, key string, value int, path ...string) ([]byte, error)

AddKeyValueInt is a variation of AddKeyValue() func. Type of new value must be an integer.

func AddKeyValueInt32 added in v1.0.1

func AddKeyValueInt32(json []byte, key string, value int32, path ...string) ([]byte, error)

AddKeyValueInt32 is a variation of AddKeyValue() func. Type of new value must be an int32.

func AddKeyValueInt64 added in v1.0.1

func AddKeyValueInt64(json []byte, key string, value int64, path ...string) ([]byte, error)

AddKeyValueInt64 is a variation of AddKeyValue() func. Type of new value must be an int64.

func AddKeyValueString

func AddKeyValueString(json []byte, key, value string, path ...string) ([]byte, error)

AddKeyValueString is a variation of AddKeyValue() func. Type of new value must be a string.

func AddKeyValueUint added in v1.0.1

func AddKeyValueUint(json []byte, key string, value uint, path ...string) ([]byte, error)

AddKeyValueUint is a variation of AddKeyValue() func. Type of new value must be an integer.

func AddKeyValueUint32 added in v1.0.1

func AddKeyValueUint32(json []byte, key string, value uint32, path ...string) ([]byte, error)

AddKeyValueUint32 is a variation of AddKeyValue() func. Type of new value must be an uint32.

func AddKeyValueUint64 added in v1.0.1

func AddKeyValueUint64(json []byte, key string, value uint64, path ...string) ([]byte, error)

AddKeyValueUint64 is a variation of AddKeyValue() func. Type of new value must be an uint64.

func AddString

func AddString(json []byte, value string, path ...string) ([]byte, error)

AddString is a variation of Add() func. Type of new value must be an string.

func AddUint added in v1.0.1

func AddUint(json []byte, value uint, path ...string) ([]byte, error)

AddUint is a variation of Add() func. Type of new value must be an integer.

func AddUint32 added in v1.0.1

func AddUint32(json []byte, value uint32, path ...string) ([]byte, error)

AddUint32 is a variation of Add() func. Type of new value must be an integer.

func AddUint64 added in v1.0.1

func AddUint64(json []byte, value uint64, path ...string) ([]byte, error)

AddUint64 is a variation of Add() func. Type of new value must be an integer.

func Delete

func Delete(json []byte, path ...string) ([]byte, error)

Delete can delete any key-value pair, array value, array, object. Path value must be provided, otherwise it will provide an error message.

Example
json := []byte(`{"user":"eco","languages":["go","java","python","C", "Cpp"]}`)

json, err := Delete(json, "languages", "1")
if err != nil {
	fmt.Println(err.Error())
	return
}
// After first deletion.
// {"user":"eco","languages":["go","python","C", "Cpp"]}

json, err = Delete(json, "user")
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

{"languages":["go","python","C", "Cpp"]}

func ErrEqual

func ErrEqual(err error, code int) bool

func Flatten

func Flatten(json []byte) []byte

Flatten is tool for formatting json strings. flattens indent formations.

Example
json := []byte(`{
	"user": "eco",
	"languages": [
		"go",
		"java",
		"python",
		"C",
		"Cpp"
	],
	"following": {
		"social": "dev.to",
		"code": "github"
	}
}`)

json = Flatten(json)
fmt.Println(string(json))
Output:

{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}

func Get

func Get(json []byte, path ...string) ([]byte, error)

Get returns the value that path has pointed. It stripes quotation marks from string values. Path can point anything, a key-value pair, a value, an array, an object. Path variable can not be null, otherwise it will provide an error message.

Example
path := []string{"following", "social"}
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}`)

value, err := Get(json, path...)
// or without path variable
// value, err := Get(json, "following", "social")
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(value))
Output:

dev.to

func GetAll

func GetAll(json []byte, keys []string, path ...string) ([]string, error)

GetAll not tested yet GetAll gets all values of path+key has pointed.

Example
json := []byte(`{"uuid":"4a1531c25d5ef124295a","personal":{"index":42,"user":"eco","language":"go"}}`)

keys := []string{"index", "language"}
allINeed, err := GetAll(json, keys, "personal")
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(allINeed)
Output:

[42 go]

func GetAllMap

func GetAllMap(json []byte, keys []string, path ...string) (map[string]string, error)

GetAllMap not tested yet GetAllMap gets all values of path+key has pointed as string to string map.

Example
json := []byte(`{"uuid":"4a1531c25d5ef124295a","personal":{"index":42,"user":"eco","language":"go"}}`)

keys := []string{"index", "language"}
allINeed, err := GetAllMap(json, keys, "personal")
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(allINeed["index"])
fmt.Println(allINeed["language"])
Output:

42
go

func GetBool

func GetBool(json []byte, path ...string) (bool, error)

GetBool is a variation of Get() func. GetBool returns the value that path has pointed as boolean. returns an error message if the value to be returned cannot be converted to an boolean

func GetBoolArray

func GetBoolArray(json []byte, path ...string) ([]bool, error)

GetBoolArray is a variation of Get() func. GetBoolArray returns the value that path has pointed as boolean slice. returns an error message if the value to be returned cannot be converted to an boolean slice.

func GetFloat

func GetFloat(json []byte, path ...string) (float64, error)

GetFloat is a variation of Get() func. GetFloat returns the value that path has pointed as float. returns an error message if the value to be returned cannot be converted to an float

func GetFloatArray

func GetFloatArray(json []byte, path ...string) ([]float64, error)

GetFloatArray is a variation of Get() func. GetFloatArray returns the value that path has pointed as float slice. returns an error message if the value to be returned cannot be converted to an float slice.

func GetInt

func GetInt(json []byte, path ...string) (int, error)

GetInt is a variation of Get() func. GetInt returns the value that path has pointed as integer. returns an error message if the value to be returned cannot be converted to an integer

func GetIntArray

func GetIntArray(json []byte, path ...string) ([]int, error)

GetIntArray is a variation of Get() func. GetIntArray returns the value that path has pointed as integer slice. returns an error message if the value to be returned cannot be converted to an integer slice.

func GetKeys

func GetKeys(json []byte, path ...string) ([]string, error)

GetKeys not tested yet Gets all keys that path has pointed.

Example
json := []byte(`{"index":42,"user":"eco","language":"go","uuid":"4a1531c25d5ef124295a","active":true}`)

keys, err := GetKeys(json)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(keys)
Output:

[index user language uuid active]

func GetKeysValues

func GetKeysValues(json []byte, path ...string) ([]string, []string, error)

GetKeysValues not tested yet Gets all keys and values that path has pointed.

Example
json := []byte(`{"index":42,"user":"eco","language":"go","uuid":"4a1531c25d5ef124295a","active":true}`)

keys, values, err := GetKeysValues(json)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(keys)
fmt.Println(values)
Output:

[index user language uuid active]
[42 eco go 4a1531c25d5ef124295a true]

func GetMap

func GetMap(json []byte, path ...string) (map[string]string, error)

GetMap Gets all keys and values pair with string to string map.

Example
json := []byte(`{"uuid":"4a1531c25d5ef124295a","personal":{"index":42,"user":"eco","language":"go"}}`)

personal, err := GetMap(json, "personal")
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(personal["index"])
fmt.Println(personal["user"])
fmt.Println(personal["language"])
Output:

42
eco
go

func GetString

func GetString(json []byte, path ...string) (string, error)

GetString is a variation of Get() func. GetString returns the value that path has pointed as string.

func GetStringArray

func GetStringArray(json []byte, path ...string) ([]string, error)

GetStringArray is a variation of Get() func. GetStringArray returns the value that path has pointed as string slice. returns an error message if the value to be returned cannot be converted to an string slice.

func GetType

func GetType(json []byte, path ...string) (string, error)

GetType returns the types of value that path has point. possible return types 'array' | 'object' | 'string' | 'boolean' | 'null' | 'number'

func GetValues

func GetValues(json []byte, path ...string) ([]string, error)

GetValues not tested yet Gets all values that path has pointed.

Example
json := []byte(`{"index":42,"user":"eco","language":"go","uuid":"4a1531c25d5ef124295a","active":true}`)

values, err := GetValues(json)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(values)
Output:

[42 eco go 4a1531c25d5ef124295a true]

func Indent

func Indent(json []byte) []byte

Indent is tool for formatting JSON strings. Adds Indentation to JSON string. It uses tab indentation.

Example
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}`)

json = Indent(json)
fmt.Println(string(json))
Output:

{
	"user": "eco",
	"languages": [
		"go",
		"java",
		"python",
		"C",
		"Cpp"
	],
	"following": {
		"social": "dev.to",
		"code": "github"
	}
}

func Insert

func Insert(json []byte, index int, value []byte, path ...string) ([]byte, error)

Insert inserts a value to an array. Path variable must point to an array, otherwise it will provide an error message.

Example
newValue := []byte(`"visual basic"`)
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"]}`)

json, err := Insert(json, 2, newValue, "languages")
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

{"user":"eco","languages":["go","java","visual basic","python","C","Cpp"]}

func InsertBool

func InsertBool(json []byte, index int, value bool, path ...string) ([]byte, error)

InsertBool is a variation of Insert() func. Type of new value must be an boolean.

func InsertFloat

func InsertFloat(json []byte, index int, value float64, path ...string) ([]byte, error)

InsertFloat is a variation of Insert() func. Type of new value must be an float64.

func InsertInt

func InsertInt(json []byte, index, value int, path ...string) ([]byte, error)

InsertInt is a variation of Insert() func. Type of new value must be an integer.

func InsertInt32 added in v1.0.1

func InsertInt32(json []byte, index int, value int32, path ...string) ([]byte, error)

InsertInt32 is a variation of Insert() func. Type of new value must be an integer.

func InsertInt64 added in v1.0.1

func InsertInt64(json []byte, index int, value int64, path ...string) ([]byte, error)

InsertInt64 is a variation of Insert() func. Type of new value must be an integer.

func InsertString

func InsertString(json []byte, index int, value string, path ...string) ([]byte, error)

InsertString is a variation of Insert() func. Type of new value must be an string.

func InsertUint added in v1.0.1

func InsertUint(json []byte, index int, value uint, path ...string) ([]byte, error)

InsertUint is a variation of Insert() func. Type of new value must be an integer.

func InsertUint32 added in v1.0.1

func InsertUint32(json []byte, index int, value uint32, path ...string) ([]byte, error)

InsertUint32 is a variation of Insert() func. Type of new value must be an integer.

func InsertUint64 added in v1.0.1

func InsertUint64(json []byte, index int, value uint64, path ...string) ([]byte, error)

InsertUint64 is a variation of Insert() func. Type of new value must be an integer.

func IsArray

func IsArray(json []byte, path ...string) (bool, error)

IsArray is a type control function. If path points to an array it will return true, otherwise it will return false. In this instance 'array' means everything that has starts and ends with square brace.

func IsEmpty

func IsEmpty(json []byte, path ...string) (bool, error)

IsEmpty is a control function. If path points to an value it will return 'value' string If path points to an array that has zero element in it, then it will return true, otherwise it will return false.

func IsObject

func IsObject(json []byte, path ...string) (bool, error)

IsObject is a type control function. If path points to an object it will return true, otherwise it will return false. In this instance 'object' means everything that has starts and ends with curly brace.

func IsValue

func IsValue(json []byte, path ...string) (bool, error)

IsValue is a type control function. If path points to an value it will return true, otherwise it will return false. In this instance 'value' means everything that has not starts and ends with any brace.

func IterateArray

func IterateArray(json []byte, callback func([]byte) (bool, error), path ...string) error

IterateArray is a callback function that can iterate any array and return value as byte slice. It stripes quotation marks from string values before return. Path value can be left blank for access main JSON.

Example
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"]}`)

err := IterateArray(json, func(value []byte) (bool, error) {
	fmt.Println(string(value))
	// this return is some kind control mechanism for escape the iteration any time you want.
	// true means keep iterate. false means stop iteration.
	// inner function returning an error for exporting inner error to outer function
	return true, nil
}, "languages")

if err != nil {
	fmt.Println(err)
	return
}
Output:

go
java
python
C
Cpp

func IterateKeyValue

func IterateKeyValue(json []byte, callback func([]byte, []byte) (bool, error), path ...string) error

IterateKeyValue is a callback function that can iterate any object and return key-value pair as byte slices. It stripes quotation marks from string values befour return. Path value can be left blank for access main JSON.

Example
json := []byte(`{"index":42,"user":"eco","language":"go","uuid":"4a1531c25d5ef124295a","active":true}`)

err := IterateKeyValue(json, func(key, value []byte) (bool, error) {
	fmt.Println("key  :", string(key))
	fmt.Println("value:", string(value))
	// this return is some kind control mechanism for escape the iteration any time you want.
	// true means keep iterate. false means stop iteration.
	// inner function returning an error for exporting inner error to outer function
	return true, nil
})

if err != nil {
	fmt.Println(err)
	return
}
Output:

key  : index
value: 42
key  : user
value: eco
key  : language
value: go
key  : uuid
value: 4a1531c25d5ef124295a
key  : active
value: true

func Length

func Length(json []byte, path ...string) (int, error)

Length function gives the length of any array or object that path has pointed.

Example
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"]}`)

length, err := Length(json, "languages")
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(length)
Output:

5

func MakeArray

func MakeArray(elements ...interface{}) []byte

MakeArray creates an array formation from given values and returns them as byte slice. Do not use any slice/array for parameter. It will accept this kind types but won't be able to make valid representation for use!

Example
years := MakeArray(2005, 2009, 2013, 2019)
// [2005,2009,2013,2019]
active := MakeArray(false, true, true, true)
// [false,true,true,true]
languages := MakeArray("visual-basic", "java", "python", "go")
// ["visual-basic","java","python","go"]

all := MakeArrayBytes(years, active, languages)
fmt.Println(string(all))
Output:

[[2005,2009,2013,2019],[false,true,true,true],["visual-basic","java","python","go"]]

func MakeArrayBool

func MakeArrayBool(values []bool) []byte

MakeArrayBool is a variation of MakeArray() func. Parameter type must be slice of boolean. For more information look MakeArray() function.

func MakeArrayBytes

func MakeArrayBytes(values ...[]byte) []byte

MakeArrayBytes is a variation of MakeArray() func. Parameter type must be slice of byte. For more information look MakeArray() function.

func MakeArrayFloat

func MakeArrayFloat(values []float64) []byte

MakeArrayFloat is a variation of MakeArray() func. Parameter type must be slice of float64. For more information look MakeArray() function.

func MakeArrayInt

func MakeArrayInt(values []int) []byte

MakeArrayInt is a variation of MakeArray() func. Parameter type must be slice of integer. For more information look MakeArray() function.

func MakeArrayString

func MakeArrayString(values []string) []byte

MakeArrayString is a variation of MakeArray() func. Parameter type must be slice of string. For more information look MakeArray() function.

func MakeEmptyArray

func MakeEmptyArray() []byte

MakeEmptyArray simply creates "[]" this as byte slice.

func MakeEmptyJson

func MakeEmptyJson() []byte

MakeEmptyJson simply creates "{}" this as byte slice.

func MakeJson

func MakeJson(keys []string, values []interface{}) []byte

MakeJson creates an JSON formation from given key and value slices, and returns them as byte slice. Do not use any slice/array for 'values' variable parameter. It will accept this kind types but won't be able to make valid representation for use!

Example
keys := []string{"username", "ip", "mac", "active"}
values := []interface{}{"eco", "192.168.1.108", "bc:ae:c5:13:84:f9", true}

user := MakeJson(keys, values)

fmt.Println(string(user))
Output:

{"username":"eco","ip":"192.168.1.108","mac":"bc:ae:c5:13:84:f9","active":true}

func MakeJsonString

func MakeJsonString(keys, values []string) []byte

MakeJsonString creates an JSON formation from given key and value string slices, and returns them as byte slice.

func MakeJsonWithMap

func MakeJsonWithMap(json map[string]string) []byte

MakeJsonWithMap creates an JSON formation from given string-string-map, and returns them as byte slice.

func ParseArray

func ParseArray(arr string) []string

ParseArray is a parse function for converting string type arrays to string slices

Example
arrayStr := `["eco", 1992, 28, false, "github", "jin"]`
array := ParseArray(arrayStr)
fmt.Printf("val:%v, type:%T\n", array, array)
Output:

val:[eco 1992 28 false github jin], type:[]string

func Set

func Set(json []byte, newValue []byte, path ...string) ([]byte, error)

Set sets the value that path has pointed. Path can point anything, a key-value pair, a value, an array, an object. Path variable can not be null, otherwise it will provide an error message.

Example
path := []string{"following"}
newValue := []byte(`["computerphile","numberphile"]`)
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}`)

json, err := Set(json, newValue, path...)
// or without path variable
// value, err := Set(json, newValue, "following")
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

{"user":"eco","languages":["go","java","python","C","Cpp"],"following":["computerphile","numberphile"]}

func SetBool

func SetBool(json []byte, newValue bool, path ...string) ([]byte, error)

SetBool is a variation of Set() func. SetBool takes the set value as boolean.

func SetFloat

func SetFloat(json []byte, newValue float64, path ...string) ([]byte, error)

SetFloat is a variation of Set() func. SetFloat takes the set value as float64.

func SetInt

func SetInt(json []byte, newValue int, path ...string) ([]byte, error)

SetInt is a variation of Set() func. SetInt takes the set value as integer.

func SetKey

func SetKey(json []byte, newKey string, path ...string) ([]byte, error)

SetKey sets the key value of key-value pair that path has pointed. Path must point to an object. otherwise it will provide an error message. Path variable can not be null,

Example
path := []string{"following"}
newKey := "sites"
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}`)

json, err := SetKey(json, newKey, path...)
// or without path variable
// json, err := Set(json, newKey, "following")
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

{"user":"eco","languages":["go","java","python","C","Cpp"],"sites":{"social":"dev.to","code":"github"}}

func SetString

func SetString(json []byte, newValue string, path ...string) ([]byte, error)

SetString is a variation of Set() func. SetString takes the set value as string.

func Store

func Store(json []byte, key string, value []byte, path ...string) ([]byte, error)

Store sets or adds a new value to the body like a real json store event

func StoreBool

func StoreBool(json []byte, key string, newValue bool, path ...string) ([]byte, error)

StoreBool is a variation of Store() func. StoreBool takes the Store value as boolean.

func StoreFloat

func StoreFloat(json []byte, key string, newValue float64, path ...string) ([]byte, error)

StoreFloat is a variation of Store() func. StoreFloat takes the Store value as float64.

func StoreInt

func StoreInt(json []byte, key string, newValue int, path ...string) ([]byte, error)

StoreInt is a variation of Store() func. StoreInt takes the Store value as integer.

func StoreString

func StoreString(json []byte, key string, newValue string, path ...string) ([]byte, error)

StoreString is a variation of Store() func. StoreString takes the Store value as string.

func Walk

func Walk(json []byte, callback func(k string, v []byte, p []string) (bool, error)) error

Types

type JO

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

func New

func New(buffer []byte) *JO

New jin_object method for same function name with interpreter

func NewJSON

func NewJSON() *JO

func ReadFile

func ReadFile(path string) (*JO, error)

ReadFile read json file and return a JSON OBject (JO)

func ReadJSONFile

func ReadJSONFile(path string) (*JO, error)

ReadJSONFile read json file and return a JSON OBject (JO)

func (*JO) Add

func (j *JO) Add(value []byte, path ...string) error

Add jin_object method for same function name with interpreter

func (*JO) AddBool

func (j *JO) AddBool(value bool, path ...string) error

AddBool jin_object method for same function name with interpreter

func (*JO) AddFloat

func (j *JO) AddFloat(value float64, path ...string) error

AddFloat jin_object method for same function name with interpreter

func (*JO) AddInt

func (j *JO) AddInt(value int, path ...string) error

AddInt jin_object method for same function name with interpreter

func (*JO) AddKeyValue

func (j *JO) AddKeyValue(key string, value []byte, path ...string) error

AddKeyValue jin_object method for same function name with interpreter

func (*JO) AddKeyValueBool

func (j *JO) AddKeyValueBool(key string, value bool, path ...string) error

AddKeyValueBool jin_object method for same function name with interpreter

func (*JO) AddKeyValueFloat

func (j *JO) AddKeyValueFloat(key string, value float64, path ...string) error

AddKeyValueFloat jin_object method for same function name with interpreter

func (*JO) AddKeyValueInt

func (j *JO) AddKeyValueInt(key string, value int, path ...string) error

AddKeyValueInt jin_object method for same function name with interpreter

func (*JO) AddKeyValueString

func (j *JO) AddKeyValueString(key string, value string, path ...string) error

AddKeyValueString jin_object method for same function name with interpreter

func (*JO) AddString

func (j *JO) AddString(value string, path ...string) error

AddString jin_object method for same function name with interpreter

func (*JO) Delete

func (j *JO) Delete(path ...string) error

Delete jin_object method for same function name with interpreter

func (*JO) Get

func (j *JO) Get(path ...string) ([]byte, error)

Get jin_object method for same function name with interpreter

func (*JO) GetAll

func (j *JO) GetAll(keys []string, path ...string) ([]string, error)

GetAll jin_object method for same function name with interpreter

func (*JO) GetAllMap

func (j *JO) GetAllMap(keys []string, path ...string) (map[string]string, error)

GetAllMap jin_object method for same function name with interpreter

func (*JO) GetBool

func (j *JO) GetBool(path ...string) (bool, error)

GetBool jin_object method for same function name with interpreter

func (*JO) GetBoolArray

func (j *JO) GetBoolArray(path ...string) ([]bool, error)

GetBoolArray jin_object method for same function name with interpreter

func (*JO) GetFloat

func (j *JO) GetFloat(path ...string) (float64, error)

GetFloat jin_object method for same function name with interpreter

func (*JO) GetFloatArray

func (j *JO) GetFloatArray(path ...string) ([]float64, error)

GetFloatArray jin_object method for same function name with interpreter

func (*JO) GetInt

func (j *JO) GetInt(path ...string) (int, error)

GetInt jin_object method for same function name with interpreter

func (*JO) GetIntArray

func (j *JO) GetIntArray(path ...string) ([]int, error)

GetIntArray jin_object method for same function name with interpreter

func (*JO) GetKeys

func (j *JO) GetKeys(path ...string) ([]string, error)

GetKeys jin_object method for same function name with interpreter

func (*JO) GetKeysValues

func (j *JO) GetKeysValues(path ...string) ([]string, []string, error)

GetKeysValues jin_object method for same function name with interpreter

func (*JO) GetMap

func (j *JO) GetMap(path ...string) (map[string]string, error)

GetMap jin_object method for same function name with interpreter

func (*JO) GetString

func (j *JO) GetString(path ...string) (string, error)

GetString jin_object method for same function name with interpreter

func (*JO) GetStringArray

func (j *JO) GetStringArray(path ...string) ([]string, error)

GetStringArray jin_object method for same function name with interpreter

func (*JO) GetType

func (j *JO) GetType(path ...string) (string, error)

GetType jin_object method for same function name with interpreter

func (*JO) GetValues

func (j *JO) GetValues(path ...string) ([]string, error)

GetValues jin_object method for same function name with interpreter

func (*JO) Insert

func (j *JO) Insert(index int, value []byte, path ...string) error

Insert jin_object method for same function name with interpreter

func (*JO) InsertBool

func (j *JO) InsertBool(index int, value bool, path ...string) error

InsertBool jin_object method for same function name with interpreter

func (*JO) InsertFloat

func (j *JO) InsertFloat(index int, value float64, path ...string) error

InsertFloat jin_object method for same function name with interpreter

func (*JO) InsertInt

func (j *JO) InsertInt(index int, value int, path ...string) error

InsertInt jin_object method for same function name with interpreter

func (*JO) InsertString

func (j *JO) InsertString(index int, value string, path ...string) error

InsertString jin_object method for same function name with interpreter

func (*JO) IsArray

func (j *JO) IsArray(path ...string) (bool, error)

IsArray jin_object method for same function name with interpreter

func (*JO) IsEmpty

func (j *JO) IsEmpty(path ...string) (bool, error)

IsEmpty jin_object method for same function name with interpreter

func (*JO) IsObject

func (j *JO) IsObject(path ...string) (bool, error)

IsObject jin_object method for same function name with interpreter

func (*JO) IsValue

func (j *JO) IsValue(path ...string) (bool, error)

IsValue jin_object method for same function name with interpreter

func (*JO) IterateArray

func (j *JO) IterateArray(callback func([]byte) (bool, error), path ...string) error

IterateArray jin_object method for same function name with interpreter

func (*JO) IterateKeyValue

func (j *JO) IterateKeyValue(callback func([]byte, []byte) (bool, error), path ...string) error

IterateKeyValue jin_object method for same function name with interpreter

func (*JO) JSON

func (j *JO) JSON() []byte

func (*JO) Set

func (j *JO) Set(newValue []byte, path ...string) error

Set jin_object method for same function name with interpreter

func (*JO) SetBool

func (j *JO) SetBool(newValue bool, path ...string) error

SetBool jin_object method for same function name with interpreter

func (*JO) SetFloat

func (j *JO) SetFloat(newValue float64, path ...string) error

SetFloat jin_object method for same function name with interpreter

func (*JO) SetInt

func (j *JO) SetInt(newValue int, path ...string) error

SetInt jin_object method for same function name with interpreter

func (*JO) SetKey

func (j *JO) SetKey(newKey string, path ...string) error

SetKey jin_object method for same function name with interpreter

func (*JO) SetString

func (j *JO) SetString(newValue string, path ...string) error

SetString jin_object method for same function name with interpreter

func (*JO) Store

func (j *JO) Store(key string, value []byte, path ...string) error

func (*JO) StoreBool

func (j *JO) StoreBool(key string, value bool, path ...string) error

StoreBool jin_object method for same function name with interpreter

func (*JO) StoreFloat

func (j *JO) StoreFloat(key string, value float64, path ...string) error

StoreFloat jin_object method for same function name with interpreter

func (*JO) StoreInt

func (j *JO) StoreInt(key string, value int, path ...string) error

StoreInt jin_object method for same function name with interpreter

func (*JO) StoreString

func (j *JO) StoreString(key string, value string, path ...string) error

StoreString jin_object method for same function name with interpreter

func (*JO) String

func (j *JO) String() string

func (*JO) Walk

func (j *JO) Walk(callback func(k string, v []byte, p []string) (bool, error)) error

type Parser

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

Parser is provides a struct for saving a JSON as nodes. Do not access or manipulate this struct. Please use methods provided for.

func Parse

func Parse(json []byte) (*Parser, error)

Parse is constructor method for creating Parsers.

func (*Parser) Add

func (p *Parser) Add(newVal []byte, path ...string) error

Add adds a value to an array. Path variable must point to an array, otherwise it will provide an error message.

Example
newValue := []byte(`"godoc.org/github.com/ecoshub"`)
json := []byte(`{"user":"eco","links":["github.com/ecoshub"]}`)

pars, err := Parse(json)
if err != nil {
	fmt.Println(err.Error())
	return
}
err = pars.Add(newValue, "links")
if err != nil {
	fmt.Println(err.Error())
	return
}
// get() returns whole JSON.
json, err = pars.Get()
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

{"user":"eco","links":["github.com/ecoshub","godoc.org/github.com/ecoshub"]}

func (*Parser) AddBool

func (p *Parser) AddBool(value bool, path ...string) error

AddBool is a variation of Add() func. Type of new value must be an boolean.

func (*Parser) AddFloat

func (p *Parser) AddFloat(value float64, path ...string) error

AddFloat is a variation of Add() func. Type of new value must be an float64.

func (*Parser) AddInt

func (p *Parser) AddInt(value int, path ...string) error

AddInt is a variation of Add() func. Type of new value must be an integer.

func (*Parser) AddKeyValue

func (p *Parser) AddKeyValue(key string, newVal []byte, path ...string) error

AddKeyValue adds a key-value pair to an object. Path variable must point to an object, otherwise it will provide an error message.

func (*Parser) AddKeyValueBool

func (p *Parser) AddKeyValueBool(key string, value bool, path ...string) error

AddKeyValueBool is a variation of AddKeyValue() func. Type of new value must be a boolean.

func (*Parser) AddKeyValueFloat

func (p *Parser) AddKeyValueFloat(key string, value float64, path ...string) error

AddKeyValueFloat is a variation of AddKeyValue() func. Type of new value must be a float64.

func (*Parser) AddKeyValueInt

func (p *Parser) AddKeyValueInt(key string, value int, path ...string) error

AddKeyValueInt is a variation of AddKeyValue() func. Type of new value must be an integer.

func (*Parser) AddKeyValueString

func (p *Parser) AddKeyValueString(key, value string, path ...string) error

AddKeyValueString is a variation of AddKeyValue() func. Type of new value must be a string.

func (*Parser) AddString

func (p *Parser) AddString(value string, path ...string) error

AddString is a variation of Add() func. Type of new value must be an string.

func (*Parser) Delete

func (p *Parser) Delete(path ...string) error

Delete can delete any key-value pair, array value, array, object. Path value must be provided, otherwise it will provide an error message.

func (*Parser) Get

func (p *Parser) Get(path ...string) ([]byte, error)

Get returns the value that path has pointed. It stripes quotation marks from string values. Path can point anything, a key-value pair, a value, an array, an object. Path variable can not be null, otherwise it will provide an error message.

Example
path := []string{"following", "social"}
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}`)

pars, err := Parse(json)
if err != nil {
	fmt.Println(err.Error())
	return
}
// get() returns whole JSON.
json, err = pars.Get(path...)
// or without path variable
// json, err := Get("following", "social")
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

dev.to

func (*Parser) GetBool

func (p *Parser) GetBool(path ...string) (bool, error)

GetBool is a variation of Get() func. GetBool returns the value that path has pointed as boolean. returns an error message if the value to be returned cannot be converted to an boolean

func (*Parser) GetBoolArray

func (p *Parser) GetBoolArray(path ...string) ([]bool, error)

GetBoolArray is a variation of Get() func. GetBoolArray returns the value that path has pointed as boolean slice. returns an error message if the value to be returned cannot be converted to an boolean slice.

func (*Parser) GetFloat

func (p *Parser) GetFloat(path ...string) (float64, error)

GetFloat is a variation of Get() func. GetFloat returns the value that path has pointed as float. returns an error message if the value to be returned cannot be converted to an float

func (*Parser) GetFloatArray

func (p *Parser) GetFloatArray(path ...string) ([]float64, error)

GetFloatArray is a variation of Get() func. GetFloatArray returns the value that path has pointed as float slice. returns an error message if the value to be returned cannot be converted to an float slice.

func (*Parser) GetInt

func (p *Parser) GetInt(path ...string) (int, error)

GetInt is a variation of Get() func. GetInt returns the value that path has pointed as integer. returns an error message if the value to be returned cannot be converted to an integer

func (*Parser) GetIntArray

func (p *Parser) GetIntArray(path ...string) ([]int, error)

GetIntArray is a variation of Get() func. GetIntArray returns the value that path has pointed as integer slice. returns an error message if the value to be returned cannot be converted to an integer slice.

func (*Parser) GetNew

func (p *Parser) GetNew(path ...string) []byte

GetNew returns the value that path has pointed. It stripes quotation marks from string values. Path can point anything, a key-value pair, a value, an array, an object. Path variable can not be null, otherwise it will provide an error message.

func (*Parser) GetString

func (p *Parser) GetString(path ...string) (string, error)

GetString is a variation of Get() func. GetString returns the value that path has pointed as string.

func (*Parser) GetStringArray

func (p *Parser) GetStringArray(path ...string) ([]string, error)

GetStringArray is a variation of Get() func. GetStringArray returns the value that path has pointed as string slice. returns an error message if the value to be returned cannot be converted to an string slice.

func (*Parser) Insert

func (p *Parser) Insert(newIndex int, newVal []byte, path ...string) error

Insert inserts a value to an array. Path variable must point to an array, otherwise it will provide an error message.

func (*Parser) InsertBool

func (p *Parser) InsertBool(index int, value bool, path ...string) error

InsertBool is a variation of Insert() func. Type of new value must be an boolean.

func (*Parser) InsertFloat

func (p *Parser) InsertFloat(index int, value float64, path ...string) error

InsertFloat is a variation of Insert() func. Type of new value must be an float64.

func (*Parser) InsertInt

func (p *Parser) InsertInt(index, value int, path ...string) error

InsertInt is a variation of Insert() func. Type of new value must be an integer.

func (*Parser) InsertString

func (p *Parser) InsertString(index int, value string, path ...string) error

InsertString is a variation of Insert() func. Type of new value must be an string.

func (*Parser) JSON

func (p *Parser) JSON() []byte

JSON returns underlying json value as byte array

func (*Parser) Set

func (p *Parser) Set(newVal []byte, path ...string) error

Set sets the value that path has pointed. Path can point anything, a key-value pair, a value, an array, an object. Path variable can not be null, otherwise it will provide an error message.

Example
path := []string{"following"}
newValue := []byte(`["computerphile","numberphile"]`)
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}`)

pars, err := Parse(json)

err = pars.Set(newValue, path...)
// or without path variable
// json, err := Set(newValue, "following")
if err != nil {
	fmt.Println(err.Error())
	return
}
// get() returns whole JSON.
json, err = pars.Get()
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

{"user":"eco","languages":["go","java","python","C","Cpp"],"following":["computerphile","numberphile"]}

func (*Parser) SetBool

func (p *Parser) SetBool(newValue bool, path ...string) error

SetBool is a variation of Set() func. SetBool takes the set value as boolean.

func (*Parser) SetFloat

func (p *Parser) SetFloat(newValue float64, path ...string) error

SetFloat is a variation of Set() func. SetFloat takes the set value as float64.

func (*Parser) SetInt

func (p *Parser) SetInt(newValue int, path ...string) error

SetInt is a variation of Set() func. SetInt takes the set value as integer.

func (*Parser) SetKey

func (p *Parser) SetKey(newKey string, path ...string) error

SetKey sets the key value of key-value pair that path has pointed. Path must point to an object. otherwise it will provide an error message. Path variable can not be null,

Example
path := []string{"following"}
newKey := "sites"
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}`)

pars, err := Parse(json)

err = pars.SetKey(newKey, path...)
// or without path variable
// json, err := Set(newKey, "following")
if err != nil {
	fmt.Println(err.Error())
	return
}

json, err = pars.Get()
if err != nil {
	fmt.Println(err.Error())
	return
}
fmt.Println(string(json))
Output:

{"user":"eco","languages":["go","java","python","C","Cpp"],"sites":{"social":"dev.to","code":"github"}}

func (*Parser) SetString

func (p *Parser) SetString(newValue string, path ...string) error

SetString is a variation of Set() func. SetString takes the set value as string.

func (*Parser) Tree

func (p *Parser) Tree() string

Tree is a simple tool for visualizing JSONs as semi-tree formation. This function returns that form as string.

Example
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}`)
parse, _ := Parse(json)
tree := parse.Tree()
fmt.Println(tree)
Output:

─ user
─ languages
	└  0
	└  1
	└  2
	└  3
	└  4
─ following
	└  social
	└  code

func (*Parser) TreeFull

func (p *Parser) TreeFull() string

TreeFull is same function with Tree, except it returns tree with values.

Example
json := []byte(`{"user":"eco","languages":["go","java","python","C","Cpp"],"following":{"social":"dev.to","code":"github"}}`)
parse, _ := Parse(json)
tree := parse.TreeFull()
fmt.Println(tree)
Output:

─ user   : "eco"
─ languages : ["go","java","python","C","Cpp"]
	└  0      : "go"
	└  1      : "java"
	└  2      : "python"
	└  3      : "C"
	└  4      : "Cpp"
─ following : {"social":"dev.to","code":"github"}
	└  social : "dev.to"
	└  code   : "github"

type Scheme

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

Scheme is a tool for creating non-nested JSONs. It provides a struct for saving a JSON scheme for later usage. Do not access or manipulate this struct. Please use methods provided for.

Example
// This Section provides examples for;
// Add(), Remove(), Save(), Restore(),
// GetOriginalKeys(), GetCurrentKeys() functions.

// MakeScheme need keys for construct a JSON scheme.
person := MakeScheme("name", "lastname", "age")

// now we can instantiate a JSON with values.
eco := person.MakeJson("eco", "hub", "28")

fmt.Println(string(eco))
// {"name":"eco","lastname":"hub","age":28}

// Add simply adds a new key to scheme.
person.Add("ip")
person.Add("location")

// now with addition above we can assign two more value.
sheldon := person.MakeJson("Sheldon", "Bloom", "42", "192.168.1.105", "USA")

fmt.Println(string(sheldon))
// {"name":"Sheldon","lastname":"Bloom","age":42,"ip":"192.168.1.105","location":"USA"}

fmt.Println(person.GetCurrentKeys())
// [name lastname age ip location]
fmt.Println(person.GetOriginalKeys())
// [name lastname age]

// for remove a certain key.
person.Remove("location")

john := person.MakeJson("John", "Wiki", "28", "192.168.1.102")
fmt.Println(string(john))
// {"name":"John","lastname":"Wiki","age":28,"ip":"192.168.1.102"}

// restores original form of scheme
person.Restore()
// and instantiate another
ted := person.MakeJson("ted", "stinson", "38")
fmt.Println(string(ted))

//save saves current keys, now this is original scheme
person.Save()
fmt.Println(person.GetCurrentKeys())
// [name lastname age ip location]
fmt.Println(person.GetOriginalKeys())
// [name lastname age]
Output:

{"name":"eco","lastname":"hub","age":28}
{"name":"Sheldon","lastname":"Bloom","age":42,"ip":"192.168.1.105","location":"USA"}
[name lastname age ip location]
[name lastname age]
{"name":"John","lastname":"Wiki","age":28,"ip":"192.168.1.102"}
{"name":"ted","lastname":"stinson","age":38}
[name lastname age]
[name lastname age]

func MakeScheme

func MakeScheme(keys ...string) *Scheme

MakeScheme is constructor method for creating Scheme's. It needs key(s) for create JSON. More information on Type Scheme example.

Example
// without Scheme
json := MakeEmptyJson()
json, _ = AddKeyValueString(json, "name", "eco")
json, _ = AddKeyValueString(json, "lastname", "hub")
json, _ = AddKeyValueString(json, "age", "28")
// json = {"name":"eco","lastname":"hub","age":28}

// with Scheme
person := MakeScheme("name", "lastname", "age")
eco := person.MakeJson("eco", "hub", "28")
fmt.Println(string(eco))
// {"name":eco,"lastname":hub,"age":28}

// And it provides a limitless instantiation
sheldon := person.MakeJson("Sheldon", "Bloom", "42")
john := person.MakeJson("John", "Wiki", "28")
fmt.Println(string(sheldon))
fmt.Println(string(john))
// {"name":"Sheldon","lastname":"Bloom","age":42}
// {"name":"John","lastname":"Wiki","age":28}
Output:

func (*Scheme) Add

func (s *Scheme) Add(key string) bool

Add adds a new key value to the current scheme. If given key is already exists it returns false, otherwise returns true. More information on Type Scheme example.

func (*Scheme) Check

func (s *Scheme) Check(json []byte) bool

Check checks the json is fitting the scheme or not

func (*Scheme) CheckAbs

func (s *Scheme) CheckAbs(json []byte) bool

CheckAbs checks the json is absolutely fitting the scheme or not

func (*Scheme) GetCurrentKeys

func (s *Scheme) GetCurrentKeys() []string

GetCurrentKeys is a simple get function for get Schemes current keys. More information on Type Scheme example.

func (*Scheme) GetOriginalKeys

func (s *Scheme) GetOriginalKeys() []string

GetOriginalKeys is a simple get function for get Schemes original keys. More information on Type Scheme example.

func (*Scheme) MakeJson

func (s *Scheme) MakeJson(values ...interface{}) []byte

MakeJson is main creation method for creating JSON's from Schemes. More information on Type Scheme example.

func (*Scheme) MakeJsonString

func (s *Scheme) MakeJsonString(values ...string) []byte

MakeJsonString is main creation method for creating JSON's from Schemes. More information on Type Scheme example.

func (*Scheme) MutateJson

func (s *Scheme) MutateJson(json []byte) ([]byte, error)

MutateJson use for mutating a json to another json with a scheme.

func (*Scheme) MutateJsonAbs

func (s *Scheme) MutateJsonAbs(json []byte) ([]byte, error)

MutateJsonAbs use for mutating a json to another json with a scheme.

func (*Scheme) Remove

func (s *Scheme) Remove(key string) bool

Remove removes the key value to the current scheme. If given key is not exists it returns false, otherwise returns true. More information on Type Scheme example.

func (*Scheme) Restore

func (s *Scheme) Restore()

Restore Schemes original form. More information on Type Scheme example.

func (*Scheme) Save

func (s *Scheme) Save()

Save saves current keys for protect them temporary changes. More information on Type Scheme example.

Jump to

Keyboard shortcuts

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