Just because it's possible, here a self-contained
parser to convert the string into an AoA in the sense
of ferreira above
use strict;
use warnings;
use Data::Dumper;
# read text from DATA
my $text = do { local $/; <DATA> };
# parse text and convert to AoA
my @stack;
while ($text =~ m/\G([\w-]+|.)/sg) {
my $tok = $1;
if ($tok eq '{' or $tok =~ /^\w/) {
push @stack, $tok;
}
elsif ($tok eq '}') { # stack: ... '{' key val(s)
my $arr = [];
while ($stack[-1] ne '{') {
unshift @$arr, pop @stack;
}
pop @stack; # '{'
push @stack, $arr;
}
}
print Dumper(\@stack);
__DATA__
{chart { {1 { {title title_1} {xlable X-lab} {ylable Y-lab}
{description desc1} {type line} {series { {1 { {x_data {1 2 3 4 5} }
{y_data {20 90 60 50 30}} } } } } } } } }
Of course, well-formedness is not tested but just
assumed. So no reasonable behaviour, when the input
does not conform to the formatting assumptions.
Trying to build the conversion to AoH into this …
while ($text =~ m/\G([\w-]+|.)/sg) {
my $tok = $1;
if ($tok eq '{' or $tok =~ /^\w/) {
push @stack, $tok;
}
elsif ($tok eq '}') {
my $arr = [];
my $allScalar = 1;
my $allHash = 1;
while ($stack[-1] ne '{') {
my $val = pop @stack;
$allScalar &&= ! ref $val;
$allHash &&= 'HASH' eq ref $val;
unshift @$arr, $val;
}
pop @stack; # '{'
if ($allScalar) {
if (@$arr != 2) {
push @stack, $arr;
}
else {
push @stack, { shift @$arr, shift @$arr };
}
}
elsif ($allHash) {
my $hash = {};
for my $h (@$arr) {
@$hash{keys %$h} = values %$h;
}
my $n = keys%$hash;
my @nSlice;
for my $i (1..$n) {
push @nSlice, $hash->{$i} if exists $hash->{$i}
}
if (@nSlice == $n) { # keys are 1 .. n
push @stack, [@nSlice];
}
else {
push @stack, $hash;
}
}
elsif (!ref(my $key = shift @$arr)) {
$arr = $arr->[0] if @$arr == 1;
push @stack, { $key => $arr };
}
else {
die Dumper(\@stack);
}
}
}
where the {{ 1 artifact is not completely eliminated, but converted to an array, under the assumption
that it might be the beginning of a longer sequence designating an 1-based array.
{
'chart' => [
{
'ylable' => 'Y-lab',
'type' => 'line',
'title' => 'title_1',
'description' => 'desc1',
'xlable' => 'X-lab',
'series' => [
{
'x_data' => [
'1',
'2',
'3',
'4',
'5'
],
'y_data' => [
'20',
'90',
'60',
'50',
'30'
]
}
]
}
]
}