How to parse arbitrary JSON data?

In JavaScript we can do something like:

const str = '{"a":true, "b":5, "c": "okay"}';
const obj = JSON.parse(str);

console.log(obj.a);
console.log(obj.b);
console.log(obj.c);

For Zig the structure of the data is required at comptime, so we need to add the struct definition before parsing:

const std = @import("std");

const str =
   \\{
   \\   "a": true,
   \\   "b": 5,
   \\   "c": "okay"
   \\}
;

const Obj = struct {
   a: bool,
   b: u8,
   c: []u8
};

pub fn main() !void {

   var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
   const gpa = general_purpose_allocator.allocator();

   const obj = try std.json.parseFromSlice(Obj, gpa, str, .{});
   defer obj.deinit();

   std.debug.print("{}\n", .{obj.value.a});
   std.debug.print("{d}\n", .{obj.value.b});
   std.debug.print("{s}\n", .{obj.value.c});

}

I am following the patterns given here and here. Having to know the structure of the JSON data beforehand means that we cannot parse any random JSON data, and if the known structure of a given JSON string is altered, then we cannot store the result as a string (i.e. on disk) without somehow storing the altered structure for use later. So I am wondering if there is any way to implement parsing of JSON strings without already knowing the structure. Any input will be appreciated.

2 Likes

I was working with some JSON myself, and I found that this worked for me

test "parse arbitrary json" {
    const json_string =
        \\ {
        \\   "a": true,
        \\   "b": 5,
        \\   "c": "okay"
        \\ }
    ;

    const parsed = try std.json.parseFromSlice(std.json.Value, std.testing.allocator, json_string, .{});
    defer parsed.deinit();

    const a = parsed.value.object.get("a").?.bool;
    const b = parsed.value.object.get("b").?.integer;
    const c = parsed.value.object.get("c").?.string;
    try std.testing.expectEqual(true, a);
    try std.testing.expect(b == 5);
    try std.testing.expectEqualStrings("okay", c);
}
4 Likes

Awesome. Thank you! I’m relieved to learn that there is a simple way to do this.