JSON-SL
view release on metacpan or search on metacpan
lib/JSON/SL/Tuba.pm view on Meta::CPAN
if ($mode !~ m{[\=\~\?\#"]}) {
die("Invalid type '$mode'. Mode must be one of [^#\"]");
}
return $tuba->_ax_opt(ord("$mode"))
}
sub accum_all {
my ($tuba,$boolean) = @_;
if (@_ != 2) {
die("Must have boolean argument!");
}
my %opts = map {
$_, $boolean
} ('=','~','#','?','"');
$tuba->accum(%opts);
}
#build convenience methods:
foreach (['key', '#'],
['string', '"'],
['number', '='],
['boolean', '?'],
['null', '~']
) {
my ($mode,$sym) = @$_;
no strict 'refs';
*{"accum_$mode"} = sub {
my ($tuba,$bool) = @_;
$tuba->_ax_opt(ord($sym), $bool);
}
}
1;
__END__
=head1 NAME
JSON::SL::Tuba - High performance SAX-like interface for JSON
=head1 SYNOPSIS
Create a very naive JSON encoder using JSON::SL::Tuba
my $JSON ||= <<'EOJ';
{
"a" : "b",
"c" : { "d" : "e" },
"f" : [ "g", "h", "i", "j" ],
"a number" : 0.4444444444,
"a (false) boolean": false,
"another (true) boolean" : true,
"a null value" : null,
"exponential" : 1.3413400E4,
"an\tescaped key" : "a u-\u0065\u0073caped value", "ש×××":"××ר××ת"
}
EOJ
# Split the 'stream' into multiple chunks to demonstrate the streaming
# feature:
my @Chunks = unpack("a(8)*", $JSON);
# Make a subclass and set up the methods..
package A::Giant::Tuba;
use base qw(JSON::SL::Tuba);
sub on_any {
my ($tuba,$info,$data) = @_;
#use constant comparisons
if ($info->{Type} == TUBA_TYPE_JSON) {
printf STDERR ("JSON DOCUMENT: %c\n\n", $info->{Mode});
return;
}
# or use the mnemonic ones
if ($info->{Key} && $info->{Mode} =~ m,[>\+],) {
printf ('"%s" : ', $info->{Key});
}
if ($info->{Type} == TUBA_TYPE_STRING) {
printf('"%s",' . "\n", $data || "<NO DATA>");
} elsif ($info->{Type} =~ m,[\[\{],) {
if ($info->{Mode} eq '+') {
print $info->{Type} . "\n";
} else {
print $JSON::SL::Tuba::CloseTokens{$info->{Type}} . ",\n";
}
} else {
if (defined $data) {
print $data . ",\n"
} else {
die ("hrrm.. what have we here?")
unless $info->{Type} == TUBA_TYPE_NULL;
print "null,\n";
}
}
}
my $o = My::Giant::Tuba->new();
$o->parse($_) for @Chunks;
Output:
JSON DOCUMENT: +
{
"a" : b,
"c" : {
"d" : e,
},
"f" : [
g,
h,
i,
j,
],
"a number" : 0.4444444444,
"a (false) boolean" : 0,
"another (true) boolean" : 1,
"a null value" : null
"exponential" : 13413.4,
"an escaped key" : a u-escaped value,
"ש×××" : ××ר××ת,
},
JSON DOCUMENT: -
=head1 DESCRIPTION
C<JSON::SL::Tuba> provides an event-based and high performance SAX-like interface
for parsing streaming JSON.
Emphasis when designing C<JSON::SL::Tuba> was the reduction of boilerplate (the
author does not have favorable experiences with SAX APIs) and high performance.
This uses the same core JSON functionality and speed as L<JSON::SL>.
To use C<JSON::SL::Tuba>, simply inherit from it and define one or more
methods to be called when a parse event occurs.
In normal cases (and this is the default), only a single method (see below)
needs to be implemented to be able to receive events.
Of course, if your application requirements are more complex, Tuba is able
to deliver you events to the resolution of a single character.
=head2 CALLBACK ARGUMENTS AND TERMINOLOGY
These are the list of methods which to implement. All methods follow a single
unified calling convention in the form of
callback($tuba, $info, $data);
where C<$tuba> is the C<JSON::SL::Tuba> instance, C<$info> is a hash reference
containing metadata about the item for which the event was received, and C<$data>
contains the actual 'data' (if applicable)
=head3 Info Hash
This hash contains metadata for determining relevant information about the current
item.
The hash and all its contents are read-only. Their contents are not valid after
the callback returns (see L</CAVEATS>). This is for both performance and
sanity reasons.
Its keys and values are as follows
=over
=item C<Type>
This is the type of JSON object for which an event was received.
The following table represents a table of type constants, and their mnemonic
symbols. The value to this key itself is a double-typed scalar which yields either
the character or the numeric value depending on the context.
Constant Mnemonic Symbol Description
=== Scalar Types ===
TUBA_TYPE_STRING " "string" value
TUBA_TYPE_KEY # hash key
TUBA_TYPE_BOOLEAN ? JSON boolean atom ('true','false')
TUBA_TYPE_NUMBER = number
TUBA_TYPE_NULL ~ JSON 'null' atom
=== Container Types ===
TUBA_TYPE_OBJECT { hash (JSON 'object')
TUBA_TYPE_LIST [ array (JSON 'list')
( run in 0.422 second using v1.01-cache-2.11-cpan-d7f47b0818f )