Zig has built-in support for JSON via the std.json module.
To convert any object into a JSON string, we use std.json.stringify(<input>, <options>, <output stream>):
const x = Place{
.lat = 51.997664,
.long = -0.740687,
};
var buf: [100]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
var string = std.ArrayList(u8).init(fba.allocator());
try std.json.stringify(x, .{}, string.writer());
See StringifyOptions struct◹ for more details about what you can pass into the options.
To parse a JSON string into an object, we can do it in two ways:
Parse into a pre-defined struct with
std.json.parse(<output type>, <tokens>, <options>):const Foo = struct { a: i32, b: bool }; const s = \\ { \\ "a": 15, "b": true \\ } ; const stream = std.json.TokenStream.init(s); const parsedData = try std.json.parse(Foo, &stream, .{});The
TokenStreamis a streaming parser that returns a stream of JSON, so we can pass them intostd.json.parse.The JSON parser requires an allocator if the input JSON data contains strings or arrays, and we need to free them after use with
std.json.parseFree:const gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer std.debug.assert(gpa.deinit()); const Foo = struct { a: i32, b: bool, c: []u8 }; const s = \\ { \\ "a": 15, "b": true, \\ "c": "hello world" \\ } ; const stream = std.json.TokenStream.init(s); const parsedData = try std.json.parse(Foo, &stream, .{ .allocator = gpa.allocator() }); defer std.json.parseFree(Foo, parsedData, .{ .allocator = gpa.allocator() });Try comment out the
defer std.json.parseFreestatement to see how’s the memory leak detection ofGeneralPurposeAllocatorworks.Checkout
ParseOptionsstruct◹ for more about what options you can pass, for example:- Set
ignore_unknown_fieldstotruewill not return any error if there is a mismatch between the output type and input data. - Set
duplicate_field_behaviorwill change the default’s behavior when there is a duplicate field in your JSON input.
- Set
Parse into a dynamic object of type
std.json.ValueTreewith a non-stream parserstd.json.Parser(<allocator>, <copy input string>):var parser = std.json.Parser.init(allocator, false); defer parser.deinit(); const s = \\ { \\ "a": 15, "b": true, \\ "c": "hello world" \\ } ; var tree = try parser.parse(s); defer tree.deinit(); // @TypeOf(tree.root) == std.json.Value // Access the fields value via .get() method var a = tree.root.Object.get("a").?; var b = tree.root.Object.get("b").?; var c = tree.root.Object.get("c").?;There is also a
dump()method that available on anystd.json.Value, to stringify an object and print it out to thestderr, best for debugging purpose:tree.root.dump();
For more details, you should read the implementation of std.json module◹, also, don’t skip the tests at the bottom of the source file. They’re super useful!