JSON-YY
view release on metacpan or search on metacpan
jset $doc, "/active", jbool 1; # true, not 1
jset $doc, "/id", jstr "007"; # "007", not 7
# iterate without materializing
my $it = jiter $doc, "/users";
while (defined(my $u = jnext $it)) {
say jgetp $u, "/name" if jis_str $u, "/name";
}
# apply RFC 6902 patch
my $patch = jdoc '[{"op":"replace","path":"/v","value":2}]';
jpatch $doc, $patch;
# apply RFC 7386 merge patch
jmerge $doc, jdoc '{"debug":null,"version":"2.0"}';
# OO decode directly to Doc
my $coder = JSON::YY->new(utf8 => 1);
my $doc = $coder->decode_doc($json);
# insert raw JSON without Perl roundtrip
jraw $doc, "/blob", '[1,2,{"nested":true}]';
# deep compare
say "equal" if jeq $doc_a, $doc_b;
say "equal" if $doc_a eq $doc_b; # overloaded
PERFORMANCE
Encode (ops/sec, higher is better)
JSON::XS JSON::YY delta
small (38B) 6.4M 6.7M +4%
medium (11KB) 26.8K 27.3K +2%
large (806KB) 153 234 +53%
Decode (ops/sec, higher is better)
JSON::XS JSON::YY delta
small (38B) 4.2M 3.5M -17%
medium (11KB) 16.9K 14.1K -16%
large (806KB) 249 267 +8%
Encode is consistently faster, especially on large payloads where
yyjson's optimized serializer dominates. Decode is slightly slower on
small/medium payloads due to Perl SV allocation overhead.
Doc API vs decode-modify-encode cycle
Perl Doc speedup
read one value 3.0M/s 3.1M/s ~equal
modify + serialize 1.6M/s 2.2M/s +42%
read from large doc 14.6K/s 73.7K/s +405%
modify large + encode 7.4K/s 47.3K/s +536%
clone subtree 15.0K/s 75.2K/s +400%
type/length check 14.4K/s 74.6K/s +418%
The Doc API avoids full Perl materialization, providing 4-5x speedup for
surgical operations on medium/large documents.
LIMITATIONS
* "canonical" mode is accepted but not yet implemented (yyjson has no
sorted-key writer).
* NaN and Infinity values cannot be encoded (croaks).
COOKBOOK
Read config, modify, write back
use JSON::YY ':doc';
my $config = jread "config.json";
jset $config, "/database/host", "newhost";
jwrite $config, "config.json";
Extract fields from large API response
my $doc = jdoc $response_body;
my $status = jgetp $doc, "/status";
my $count = jlen $doc, "/data/items";
my $first = jgetp $doc, "/data/items/0/name";
Find user by name in array
my $user = jfind $doc, "/users", "/name", "Alice";
say jgetp $user, "/email" if defined $user;
Build document from scratch
my $doc = jfrom {};
jset $doc, "/name", "My App";
jset $doc, "/version", jnum 1;
jset $doc, "/features", jarr;
jset $doc, "/features/-", "auth";
jset $doc, "/features/-", "logging";
jset $doc, "/debug", jbool 0;
jwrite $doc, "output.json";
Apply incremental updates (merge patch)
my $doc = jread "state.json";
jmerge $doc, jdoc $incoming_patch_json;
jwrite $doc, "state.json";
Debug: show all paths
my @paths = jpaths $doc, "";
say "$_ = ", jencode $doc, $_ for @paths;
Type-safe assertions
die "expected array" unless jis_arr $doc, "/items";
die "expected string" unless jis_str $doc, "/name";
Compare two documents
die "configs differ" if $prod ne $staging; # overloaded
# or explicitly:
die "differ" unless jeq $prod, $staging;
CHEATSHEET
# --- Import ---
use JSON::YY qw(encode_json decode_json); # functional
use JSON::YY ':doc'; # Doc API keywords
# --- Encode/Decode ---
encode_json $data decode_json $json
$coder->encode($data) $coder->decode($json)
decode_json_ro $json # zero-copy readonly
# --- Doc lifecycle ---
jdoc $json # parse JSON string -> Doc
jfrom $perl_data # Perl data -> Doc
jread $file # read JSON file -> Doc
( run in 0.793 second using v1.01-cache-2.11-cpan-39bf76dae61 )