http://www.perlmonks.org?node_id=604537


in reply to Keyed list in perl

Your syntax and data structure looks very much like an s-expression (or Lisp list) with some minor differences: like braces instead of parentheses.

The following is a partial solution to your question after massaging the input a little bit. First, braces are replaced by parentheses. Then, all underscores have been replaced by hyphens (this is due to a current limitation of the module used below). And the input file looks like this:

(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))))))))))

There is in CPAN a quite recent module named Data::SExpression (and there is some problem with the current version 0.33 and so I recommend installing the former — for example, say install NELHAGE/Data-SExpression-0.32.tar.gz in the CPAN shell instead of just install Data::SExpression). This module is able to parse the input above.

But that does not mean it would turn into a handy data structure. Instead it is all composed of array refs that made things quite difficult to access.

[ "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]]], ], ], ], ], ], ], ]

Making some assumptions on your data, I wrote some code to turn that into a nice hash of hashes. Like this:

{ chart => { description => "desc1", series => { "x-data" => [1, 2, 3, 4, 5], "y-data" => [20, 90, 60, 50, 30] }, title => "title-1", type => "line", xlable => "X-lab", ylable => "Y-lab", }, }
and then your request
Now i want to get the value of x_data (1 2 3 4 5) and y_data (20 90 60 50 30)
turned into a trivial thing:
use Data::Dump qw(dump); print "x_data: ", dump($keyed_list->{chart}->{series}->{"x-data"}), "\ +n"; print "y_data: ", dump($keyed_list->{chart}->{series}->{"y-data"}), "\ +n"; # which outputs #x_data: [1, 2, 3, 4, 5] #y_data: [20, 90, 60, 50, 30]
The entire code which I experimented against your data is:
package Data::SExpression::Special; use Data::SExpression; our @ISA = qw(Data::SExpression); sub new_symbol { shift; return shift; } package main; use File::Slurp qw(read_file); my $file = shift; my $ds = Data::SExpression::Special->new(); my $sexp = $ds->read(read_file($file)); use Data::Dump qw(dump); print dump($sexp); # outputs this mess: #[ # "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, 5 +0, 30]]], # ], # ], # ], # ], # ], # ], #] # converts [ *a => $v ] to ( *a => to_keyed_list($v) ) sub to_keyed_pair { my $sexp = shift; my $k = $sexp->[0]; my $v = $sexp->[1]; my $val; if (ref $v eq 'ARRAY' && ref $v->[0] eq 'ARRAY' && $v->[0]->[0] eq '1' && ref $v->[0]->[1] eq 'ARRAY') { # if is something like [ [ 1, [ + @list_of_pairs ] ] ] $val = to_keyed_list($v->[0]->[1]); } else { $val = $v; } return ($k, $val); } sub to_keyed_list { my $list = shift; my %hash; for (@$list) { my ($k, $v) = to_keyed_pair($_); $hash{$k} = $v; } return \%hash; } my $keyed_list = to_keyed_list([ $sexp ]); print dump($keyed_list); # now that is a easy-to-access data structure #{ # chart => { # description => "desc1", # series => { "x-data" => [1, 2, 3, 4, 5], # "y-data" => [20, 90, 60, 50, 30] }, # title => "title-1", # type => "line", # xlable => "X-lab", # ylable => "Y-lab", # }, #} #Now i want to get the value of x_data (1 2 3 4 5) and y_data (20 90 6 +0 50 30) print "x_data: ", dump($keyed_list->{chart}->{series}->{"x-data"}), "\ +n"; print "y_data: ", dump($keyed_list->{chart}->{series}->{"y-data"}), "\ +n"; # and then you got #x_data: [1, 2, 3, 4, 5] #y_data: [20, 90, 60, 50, 30]