How to parse JSON object with key containing dash

Sure there is! In Zig you can declare identifiers that contain character sequences that would otherwise be invalid if you wrap the names in @"...": Documentation - The Zig Programming Language

This works for struct field names too, and you can access those fields using the same @"..." syntax, or the @field() builtin:

$ cat field.zig 
const std = @import("std");

const FancyName = struct {
    @"field$name": []const u8,
};

pub fn main() void {
    const fns: FancyName = .{ .@"field$name" = "test" };
    // both of these do the same thing
    std.debug.print("using @\"...\": {s}\n", .{fns.@"field$name"});
    std.debug.print("using @field(): {s}\n", .{@field(fns, "field$name")});
}

$ zig build-exe field.zig && ./field
using @"...": test
using @field(): test

So, for your example above, you can use this code:

$ cat json.zig 
const std = @import("std");

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = arena.allocator();

    const Response = struct {
        headers: struct {
            Host: []const u8,
            @"User-Agent": []const u8,
        },
    };
    const input =
        \\ {
        \\ "headers": {
        \\   "Accept": "application/vnd.github.v3+json",
        \\   "Host": "httpbin.org",
        \\   "User-Agent": "my http client",
        \\   "X-Amzn-Trace-Id": "Root=1-632f00bb-04724a8831e8b65c47175bba"
        \\ } }
    ;
    var stream = std.json.TokenStream.init(input);
    const resp = try std.json.parse(Response, &stream, .{
        .allocator = allocator,
        .ignore_unknown_fields = true,
    });
    std.log.info("Host: {s}", .{resp.headers.Host});
    std.log.info("User-Agent: {s}", .{resp.headers.@"User-Agent"});
}

$ zig build-exe json.zig && ./json
info: Host: httpbin.org
info: User-Agent: my http client
3 Likes