A work-in-progress JSON parser written on pure V. It aims to replace CJSON and provides a cleaner and simple-to-use API for encoding and decoding JSON.
module main
import jisoni
import http
fn main() {
// Decoding
resp := http.get('https://example.com')?
// raw decode
raw_person := jisoni.raw_decode(resp.text)?
// decode to a type
person2 := jisoni.decode<Person>(resp.text)?
//Navigating
person := raw_person.as_map()
name := person['name'].as_str() // Bob
age := person['age'].as_int() // 19
pi := person['pi'].as_f() // 3.14....
//Constructing an `Any` type
mut me := map[string]jisoni.Any
me['name'] = 'Ned Poolz'
me['age'] = 18
mut arr := []jisoni.Any{}
arr << 'rock'
arr << 'papers'
arr << jisoni.null()
arr << 12
me['interests'] = arr
mut pets := map[string]jisoni.Any
pets['Sam'] = 'Maltese Shitzu'
me['pets'] = pets
// Stringify to JSON
println(me.str())
//{"name":"Ned Poolz","age":18,"interests": ["rock", "papers", "scissors"],"pets":{"Sam":"Maltese"}}
// Encode a struct/type to JSON
encoded_json := jisoni.encode<Person>(person2)
}
decode<T>
and encode<T>
In order to use the decode<T>
and encode<T>
function, you need to explicitly define two methods: from_json
and to_json
. from_json
accepts a jisoni.Any
argument and inside of it you need to map the fields you're going to put into the type. As for to_json
method, you just need to map the values into jisoni.Any
and turn it into a string.
struct Person {
mut:
name string
age int = 20
pets []string
}
fn (mut p Person) from_json(f Any) Person {
obj := f.as_map()
for k, v in obj {
match k {
'name' { p.name = v.as_str() }
'age' { p.age = v.as_int() }
'pets' { p.pets = v.as_arr().map(it.as_str()) }
else {}
}
}
return p
}
fn (p Person) to_json() string {
mut obj := map[string]Any
obj['name'] = p.name
obj['age'] = p.age
obj['pets'] = p.pets
return obj.str()
}
fn main() {
resp := os.read_file('./person.json')?
person := jisoni.decode<Person>(resp)
println(person) // Person{name: 'Bob', age: 28, pets: ['Floof']}
person_json := jisoni.encode<Person>(person)
println(person_json) // {"name": "Bob", "age": 28, "pets": ["Floof"]}
}
Jisoni cannot use struct tags just like when you use the json
module. However, it emits an Any
type when decoding so it can be flexible on the way you use it.
Jisoni have a null
value for differentiating an undefined value and a null value. Use is
for verifying the field you're using is a null.
fn (mut p Person) from_json(f Any) Person {
obj := f.as_map()
if obj['age'] is jisoni.Null {
// use a default value
p.age = 10
}
return p
}
In json
, you can specify the field name you're mapping into the struct field by specifying a json:
tag. In Jisoni, just simply cast the base field into a map (as_map()
) and get the value of the field you wish to put into the struct/type.
fn (mut p Person) from_json(f jisoni.Any) Person {
obj := f.as_map()
p.name = obj['nickname'].as_str()
return p
}
fn (mut p Person) to_json() string {
obj := f.as_map()
obj['nickname'] = p.name
return obj.str()
}
Getting undefined values has the same behavior as regular V types. If you're casting a base field into map[string]Any
and fetch an undefined entry/value, it simply returns empty. As for the []Any
, it returns an index error.
Jisoni provides methods for turning Any
types into usable types. The following list shows the possible outputs when casting a value to an incompatible type.
as_arr()
) will return an array with the value as the content.as_map()
) will return a map with the value as the content.as_str()
) will return the stringified representation of the value.as_int()
/as_f()
) will return zero.Licensed under MIT
Testing instructions will be updated soon.
(c) 2020- Ned Palacios
fn (mut obj map[string]Any) insert_str(key, val string)
Inserts a string into the map.
fn (mut obj map[string]Any) insert_int(key string, val int)
Inserts an int into the map.
fn (mut obj map[string]Any) insert_f(key string, val f64)
Inserts a float into the map.
fn (mut obj map[string]Any) insert_null(key string)
Inserts a null into the map.
fn (mut obj map[string]Any) insert_bool(key string, val bool)
Inserts a bool into the map.
fn (mut obj map[string]Any) insert_map(key string, val map[string]Any)
Inserts a map into the map.
fn (mut obj map[string]Any) insert_arr(key string, val []Any)
Inserts an array into the map.
fn (mut arr []Any) insert_str(val string)
Inserts a string into the array.
fn (mut arr []Any) insert_int(val int)
Inserts an int into the array.
fn (mut arr []Any) insert_f(val f64)
Inserts a float into the array.
fn (mut arr []Any) insert_null()
Inserts a null into the array.
fn (mut arr []Any) insert_bool(val bool)
Inserts a bool into the array.
fn (mut arr []Any) insert_map(val map[string]Any)
Inserts a map into the array.
fn (mut arr []Any) insert_arr(val []Any)
Inserts an array into the array.
type Any = Null | []Any | any_float | any_int | bool | f64 | int | map[string]Any | string
Any
is a sum type that lists the possible types to be decoded and used.
fn (f Any) str() string
String representation of the Any
type.
fn (f Any) as_map() map[string]Any
Use Any
as a map.
fn (f Any) as_str() string
Use Any
as a string.
fn (f Any) as_int() int
Use Any
as an integer.
fn (f Any) as_f() f64
Use Any
as a float.
fn (f Any) as_arr() []Any
Use Any
as an array.
struct Null {
}
Null
struct is a simple representation of the null
value in JSON.
fn (flds map[string]Any) str() string
String representation of the map[string]Any
.
fn (flds []Any) str() string
String representation of the []Any
.
fn raw_decode(src string) ?Any
Decodes a JSON string into an Any
type. Returns an option.
fn decode<T>(src string) T
A generic function that decodes a JSON string into the target type.
fn encode<T>(typ T) string
A generic function that encodes a type into a JSON string.
fn null() Null
A simple function that returns Null
struct. For use on constructing an Any
object.