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.
- Another reason to use JSON.
- Some escaping removed for readability.