The name
json2was chosen to avoid any unwanted potential conflicts with the existing codegen tailored for the mainjsonmodule which is powered by CJSON.
x.json2 is an experimental JSON parser written from scratch on V.
import x.json2
import time
struct Person {
mut:
name string
age ?int = 20
birthday time.Time
deathday ?time.Time
}
fn main() {
mut person := Person{
name: 'Bob'
birthday: time.now()
}
person_json := json2.encode[Person](person)
// person_json == {"name": "Bob", "age": 20, "birthday": "2022-03-11T13:54:25.000Z"}
}
Enums encode as strings by default. Use @[json_as_number] on an enum to emit
its integer value instead.
import x.json2
import time
struct Person {
mut:
name string
age ?int = 20
birthday time.Time
deathday ?time.Time
}
fn main() {
resp := '{"name": "Bob", "age": 20, "birthday": "${time.now()}"}'
person := json2.decode[Person](resp)!
// struct Person {
// mut:
// name "Bob"
// age 20
// birthday "2022-03-11 13:54:25"
// deathday "2022-03-11 13:54:25"
// }
}
decode[T] is smart and can auto-convert the types of struct fields - this means examples below will have the same result
Embedded struct fields are decoded from the surrounding object, including reference fields.
json2.decode[Person]('{"name": "Bob", "age": 20, "birthday": "2022-03-11T13:54:25.000Z"}')!
json2.decode[Person]('{"name": "Bob", "age": 20, "birthday": "2022-03-11 13:54:25.000"}')!
json2.decode[Person]('{"name": "Bob", "age": "20", "birthday": 1647006865}')!
json2.decode[Person]('{"name": "Bob", "age": "20", "birthday": "1647006865"}}')!
import x.json2
import net.http
fn main() {
resp := http.get('https://reqres.in/api/products/1')!
// This returns an Any type
raw_product := json2.decode[json2.Any](resp.body)!
}
x.json2 now exposes low-level scanners that let you process JSON token by
token instead of materializing the whole tree first.
Use new_scanner() for in-memory strings:
import x.json2
fn main() {
mut scanner := json2.new_scanner('{"items":[1,2,3]}')
for {
token := scanner.next()!
if token.is_eof() {
break
}
println('${token.kind}: ${token.literal()}')
}
}
Use new_reader_scanner() to stream tokens from a file or any io.Reader:
import os
import x.json2
fn main() {
mut file := os.open('huge.json')!
defer {
file.close()
}
mut scanner := json2.new_reader_scanner(reader: file)
defer {
scanner.free()
}
for {
token := scanner.next()!
if token.is_eof() {
break
}
if token.kind == .str && token.literal() == 'id' {
println('found an id key')
}
}
}
Any type / Navigatingimport x.json2
import net.http
fn main() {
resp := http.get('https://reqres.in/api/products/1')!
raw_product := json2.decode[json2.Any](resp.body)!
product := raw_product.as_map()
data := product['data'] as map[string]json2.Any
id := data['id'].int() // 1
name := data['name'].str() // cerulean
year := data['year'].int() // 2000
}
Any typeimport x.json2
fn main() {
mut me := map[string]json2.Any{}
me['name'] = 'Bob'
me['age'] = 18
mut arr := []json2.Any{}
arr << 'rock'
arr << 'papers'
arr << json2.null
arr << 12
me['interests'] = arr
mut pets := map[string]json2.Any{}
pets['Sam'] = 'Maltese Shitzu'
me['pets'] = pets
// Stringify to JSON
println(me.str())
//{
// "name":"Bob",
// "age":18,
// "interests":["rock","papers","scissors",null,12],
// "pets":{"Sam":"Maltese"}
//}
}
x.json2 has a separate Null type for differentiating an undefined value and a null value.
To verify that the field you're accessing is a Null, use [typ] is json2.Null.
fn (mut p Person) from_json(f json2.Any) {
obj := f.as_map()
if obj['age'] is json2.Null {
// use a default value
p.age = 10
}
}
x.json2 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_array() will return an array with the value as the content.as_map()) will return a map with the value as the content.str()) will return the
JSON string representation of the value.int()/i64()/f32()/f64()) will return zero.To be more performant, json2, in PR 20052, decided to use buffers directly instead of Writers.
If you want to use Writers you can follow the steps below:
mut sb := strings.new_builder(64)
mut buffer := []u8{}
json2.encode_value(, mut buffer)!
sb.write(buffer)!
unsafe { buffer.free() }