Reputation: 1237
jQuery.ajax()
encodes complex JavaScript objects into a query string like this:
?a[b][]=1&a[b][]=2&a[c]=3
I would like to decode this into a Perl data structure like this:
{ a=>{ b=>[1,2], c=>3 } }
PHP does this by default. Is there a way to also do it in a Perl CGI script? Not necessarily using CGI.pm; I can install any library I want.
So far I can only decode one-dimensional arrays because the CGI module's param()
function can return an array.
Upvotes: 2
Views: 330
Reputation: 385655
Have you considered submitting your data as JSON instead? It's simply a question of replacing
data: data
with
data: JSON.stringify(data)
You could even switch to a POST
to avoid URI-encoding, URI-decoding and query size limits (although POST semantics are different than GET semantics).
method: "POST",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify(data)
Anyway, the following should do the trick:
use Data::Diver qw( DiveVal );
use List::Util qw( pairs ); # 1.29+
use URI qw( );
my $url = URI->new('?a[b][]=1&a[b][]=2&a[c]=3', 'http');
my %data;
PAIR: for ( pairs( $url->query_form() ) ) {
my ($k, $v) = @$_;
my ( @k, $push );
for (my $k_ = $k) { # Basically C<< my $_ = $k; >>
s/^(\w+)//
or warn("Can't handle key $k\n"), next PAIR;
push @k, $1;
push @k, $1 while s/^\[(\w+)\]//;
$push = s/^\[\]//;
$_ eq ""
or warn("Can't handle key $k\n"), next PAIR;
}
if ($push) {
push @{ DiveVal(\%data, @k) }, $v;
} else {
DiveVal(\%data, @k) = $v;
}
}
Versions of Perl older than 5.16 need a workaround. Replace
use Data::Diver qw( DiveVal );
push @{ DiveVal(\%data, @k) }, $v;
with
use Data::Diver qw( DiveRef DiveVal );
push @{ ${ DiveRef(\%data, @k) } }, $v;
Note that the format is ambiguous[1]. For example, the following two expressions produce the same result (a[0][x]=3
[2]):
jQuery.param( { a: [ { x: 3 } ] } )
jQuery.param( { a: { "0": { x: 3 } } } )
My code will reproduce the former. Numeric keys are always considered to be array indexes.
Upvotes: 4
Reputation: 118605
PHP interprets a query string like foo[]=123&foo[]=234&foo[]=345
differently than all of the Perl web frameworks. I once built a PHP plugin for Mojolicious and had to work out a lot of those differences. You can find a summary of those differences and some working code (working for up to 2-level hashes, anyway) to convert Perl params to PHP-style params here. Perhaps you could adapt it for your use case.
Upvotes: 1