std.json — Parsing e Serialização JSON
O módulo std.json fornece funcionalidades completas para trabalhar com JSON no Zig. Ele inclui um parser que pode desserializar JSON diretamente em structs tipadas do Zig (usando parseFromSlice) e um sistema de serialização que converte valores Zig em JSON (usando stringify). A abordagem é fortemente tipada e verificada em tempo de compilação.
Visão Geral
const std = @import("std");
const json = std.json;
O sistema JSON do Zig oferece duas abordagens:
- Tipada: Desserializa diretamente em structs Zig — ideal quando a estrutura é conhecida
- Dinâmica: Usa
json.Valuepara JSON de estrutura desconhecida
Tipos Principais
json.Value
Representação dinâmica de qualquer valor JSON:
pub const Value = union(enum) {
null,
bool: bool,
integer: i64,
float: f64,
number_string: []const u8,
string: []const u8,
array: Array,
object: ObjectMap,
};
Funções Principais
// Parse tipado — desserializa em struct T
pub fn parseFromSlice(
comptime T: type,
allocator: Allocator,
input: []const u8,
options: ParseOptions,
) !Parsed(T)
// Parse dinâmico — retorna json.Value
pub fn parseFromSlice(
json.Value,
allocator: Allocator,
input: []const u8,
options: ParseOptions,
) !Parsed(json.Value)
// Serialização — converte valor Zig para JSON
pub fn stringify(value: anytype, options: StringifyOptions, writer: anytype) !void
// Serialização para string alocada
pub fn stringifyAlloc(allocator: Allocator, value: anytype, options: StringifyOptions) ![]u8
Exemplo 1: Desserialização Tipada
const std = @import("std");
const Usuario = struct {
nome: []const u8,
idade: u32,
email: ?[]const u8 = null,
ativo: bool = true,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const json_str =
\\{
\\ "nome": "Maria Silva",
\\ "idade": 28,
\\ "email": "maria@exemplo.com",
\\ "ativo": true
\\}
;
const parsed = try std.json.parseFromSlice(Usuario, allocator, json_str, .{});
defer parsed.deinit();
const user = parsed.value;
const stdout = std.io.getStdOut().writer();
try stdout.print("Nome: {s}\n", .{user.nome});
try stdout.print("Idade: {d}\n", .{user.idade});
if (user.email) |email| {
try stdout.print("Email: {s}\n", .{email});
}
try stdout.print("Ativo: {}\n", .{user.ativo});
}
Exemplo 2: Parse Dinâmico e Navegação
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const json_str =
\\{
\\ "servidor": {
\\ "host": "localhost",
\\ "porta": 8080,
\\ "tls": false
\\ },
\\ "banco": {
\\ "url": "postgres://localhost/app",
\\ "pool_size": 10
\\ },
\\ "tags": ["web", "api", "prod"]
\\}
;
const parsed = try std.json.parseFromSlice(std.json.Value, allocator, json_str, .{});
defer parsed.deinit();
const root = parsed.value;
const stdout = std.io.getStdOut().writer();
// Navega na estrutura
if (root.object.get("servidor")) |servidor| {
if (servidor.object.get("host")) |host| {
try stdout.print("Host: {s}\n", .{host.string});
}
if (servidor.object.get("porta")) |porta| {
try stdout.print("Porta: {d}\n", .{porta.integer});
}
}
// Itera sobre array
if (root.object.get("tags")) |tags| {
try stdout.writeAll("Tags: ");
for (tags.array.items, 0..) |tag, i| {
if (i > 0) try stdout.writeAll(", ");
try stdout.print("{s}", .{tag.string});
}
try stdout.writeAll("\n");
}
}
Exemplo 3: Serialização de Structs para JSON
const std = @import("std");
const Resposta = struct {
status: u16,
mensagem: []const u8,
dados: ?Dados = null,
const Dados = struct {
itens: []const Item,
total: u32,
};
const Item = struct {
id: u32,
nome: []const u8,
preco: f64,
};
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const itens = [_]Resposta.Item{
.{ .id = 1, .nome = "Teclado", .preco = 149.90 },
.{ .id = 2, .nome = "Mouse", .preco = 79.50 },
.{ .id = 3, .nome = "Monitor", .preco = 1899.00 },
};
const resposta = Resposta{
.status = 200,
.mensagem = "Sucesso",
.dados = .{
.itens = &itens,
.total = 3,
},
};
// Serializa com formatação
const json_output = try std.json.stringifyAlloc(allocator, resposta, .{
.whitespace = .indent_2,
});
defer allocator.free(json_output);
const stdout = std.io.getStdOut().writer();
try stdout.print("{s}\n", .{json_output});
}
Opções de Configuração
ParseOptions
.{
.ignore_unknown_fields = true, // Ignora campos não mapeados
.allocate = .alloc_always, // Aloca strings
}
StringifyOptions
.{
.whitespace = .indent_2, // JSON formatado (2 espaços)
.whitespace = .indent_4, // JSON formatado (4 espaços)
.whitespace = .minified, // JSON compacto (padrão)
.emit_null_optional_fields = false, // Omite campos null
}
Módulos Relacionados
- std.json Parsing — Detalhes de parsing JSON
- std.json Stringify — Detalhes de serialização JSON
- std.fmt — Formatação de strings
- std.mem — Operações de memória