2020-12-06 00:54:41 +03:00
|
|
|
> The name `json2` was chosen to avoid any unwanted potential conflicts with the
|
2020-11-29 16:54:45 +03:00
|
|
|
> existing codegen tailored for the main `json` module which is powered by CJSON.
|
2020-09-10 13:05:40 +03:00
|
|
|
|
2020-11-29 16:54:45 +03:00
|
|
|
`x.json2` is an experimental JSON parser written from scratch on V.
|
2020-09-10 13:05:40 +03:00
|
|
|
|
|
|
|
## Usage
|
2022-12-14 11:21:29 +03:00
|
|
|
#### encode[T]
|
|
|
|
|
|
|
|
```v
|
|
|
|
import x.json2
|
|
|
|
import time
|
|
|
|
|
|
|
|
struct Person {
|
|
|
|
mut:
|
|
|
|
name string
|
|
|
|
age ?int = 20
|
|
|
|
birthday time.Time
|
2023-02-24 11:54:45 +03:00
|
|
|
deathday ?time.Time
|
2022-12-14 11:21:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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"}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### decode[T]
|
|
|
|
|
|
|
|
```v
|
|
|
|
import x.json2
|
|
|
|
import time
|
|
|
|
|
|
|
|
struct Person {
|
|
|
|
mut:
|
|
|
|
name string
|
|
|
|
age ?int = 20
|
|
|
|
birthday time.Time
|
2023-02-24 11:54:45 +03:00
|
|
|
deathday ?time.Time
|
2022-12-14 11:21:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2023-02-24 11:54:45 +03:00
|
|
|
resp := '{"name": "Bob", "age": 20, "birthday": "${time.now()}"}'
|
2022-12-14 11:21:29 +03:00
|
|
|
person := json2.decode[Person](resp)!
|
|
|
|
/*
|
|
|
|
struct Person {
|
|
|
|
mut:
|
|
|
|
name "Bob"
|
|
|
|
age 20
|
|
|
|
birthday "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
|
|
|
|
|
|
|
|
```v ignore
|
|
|
|
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"}}')!
|
|
|
|
```
|
|
|
|
|
|
|
|
#### raw decode
|
|
|
|
|
|
|
|
```v
|
2020-09-10 13:05:40 +03:00
|
|
|
import x.json2
|
2020-11-18 20:28:28 +03:00
|
|
|
import net.http
|
2020-09-10 13:05:40 +03:00
|
|
|
|
|
|
|
fn main() {
|
2022-12-14 11:21:29 +03:00
|
|
|
resp := http.get('https://reqres.in/api/products/1')!
|
2020-09-10 13:05:40 +03:00
|
|
|
|
2022-12-14 11:21:29 +03:00
|
|
|
// This returns an Any type
|
|
|
|
raw_product := json2.raw_decode(resp.body)!
|
|
|
|
}
|
|
|
|
```
|
|
|
|
#### Casting `Any` type / Navigating
|
|
|
|
```v
|
|
|
|
import x.json2
|
|
|
|
import net.http
|
2020-09-10 13:05:40 +03:00
|
|
|
|
2022-12-14 11:21:29 +03:00
|
|
|
fn main() {
|
|
|
|
resp := http.get('https://reqres.in/api/products/1')!
|
|
|
|
|
|
|
|
raw_product := json2.raw_decode(resp.body)!
|
|
|
|
|
|
|
|
product := raw_product.as_map()
|
|
|
|
data := product['data'] as map[string]json2.Any
|
2020-09-10 13:05:40 +03:00
|
|
|
|
2022-12-14 11:21:29 +03:00
|
|
|
id := data['id'].int() // 1
|
|
|
|
name := data['name'].str() // cerulean
|
|
|
|
year := data['year'].int() // 2000
|
|
|
|
}
|
|
|
|
```
|
|
|
|
#### Constructing an `Any` type
|
|
|
|
```v
|
|
|
|
import x.json2
|
|
|
|
|
|
|
|
fn main() {
|
2021-02-05 20:50:28 +03:00
|
|
|
mut me := map[string]json2.Any{}
|
|
|
|
me['name'] = 'Bob'
|
|
|
|
me['age'] = 18
|
2020-09-10 13:05:40 +03:00
|
|
|
|
2021-02-05 20:50:28 +03:00
|
|
|
mut arr := []json2.Any{}
|
|
|
|
arr << 'rock'
|
|
|
|
arr << 'papers'
|
|
|
|
arr << json2.null
|
|
|
|
arr << 12
|
2020-09-10 13:05:40 +03:00
|
|
|
|
2021-02-05 20:50:28 +03:00
|
|
|
me['interests'] = arr
|
2020-09-10 13:05:40 +03:00
|
|
|
|
2021-02-05 20:50:28 +03:00
|
|
|
mut pets := map[string]json2.Any{}
|
|
|
|
pets['Sam'] = 'Maltese Shitzu'
|
|
|
|
me['pets'] = pets
|
2020-09-10 13:05:40 +03:00
|
|
|
|
2021-02-05 20:50:28 +03:00
|
|
|
// Stringify to JSON
|
|
|
|
println(me.str())
|
|
|
|
//{
|
|
|
|
// "name":"Bob",
|
|
|
|
// "age":18,
|
|
|
|
// "interests":["rock","papers","scissors",null,12],
|
|
|
|
// "pets":{"Sam":"Maltese"}
|
|
|
|
//}
|
2020-09-10 13:05:40 +03:00
|
|
|
}
|
|
|
|
```
|
|
|
|
### Null Values
|
2022-12-14 11:21:29 +03:00
|
|
|
`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`.
|
2020-09-10 13:05:40 +03:00
|
|
|
|
2020-11-18 20:28:28 +03:00
|
|
|
```v ignore
|
2020-09-10 13:05:40 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Casting a value to an incompatible type
|
2020-11-18 20:28:28 +03:00
|
|
|
`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.
|
2020-09-10 13:05:40 +03:00
|
|
|
|
|
|
|
1. Casting non-array values as array (`arr()`) will return an array with the value as the content.
|
|
|
|
2. Casting non-map values as map (`as_map()`) will return a map with the value as the content.
|
2020-12-06 00:54:41 +03:00
|
|
|
3. Casting non-string values to string (`str()`) will return the
|
2020-11-29 16:54:45 +03:00
|
|
|
JSON string representation of the value.
|
|
|
|
4. Casting non-numeric values to int/float (`int()`/`i64()`/`f32()`/`f64()`) will return zero.
|