ovedpo15 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm a beginner in Perl.
I would like to use the JSON module in order to create one. In other words, I'm trying to build a function which creates a JSON file:

Consider the following structure of a JSON file:

{ "time": 123456 "id": 56789 "data": [{"key": "first" , "value": "1" , "format": "1.5.6" , "ver +sion": "5.4"}, {"key": "two" , "value": "2" , "format": "1.4.6" , "versi +on": "5.4}, {"key": "five" , "value": "5" , "format": "1.5.9" , "vers +ion": "5.1"}] }
This is the structure I would like the JSON file to be. Also, consider that the data is in a file that each one if its lines look like this:
first,1,1.5.6,5.4 two,2,1.4.6,5.4 five,5,1.5.9,5.1

So the array of objection that JSON file should contain is represented as each line of the previous file. I know how to split each line and push into a hash. So I would like to ask the two following questions:

1. Is there a better way to than splitting and pushing into a hash?
2. Main question: After I get a hash, how can I convert it to be of JSON file type while not forgetting to add the primitive values of "time" & "id"?
I saw some examples of how to convert JSON to hash in Perl but didn't find an example of how to use the other way.

Thank you and have a great day.

Replies are listed 'Best First'.
Re: Create JSON file in specific format
by choroba (Cardinal) on Apr 24, 2018 at 15:33 UTC
    Just create a Perl structure corresponding to the expected JSON and use the JSON module to encode it to JSON. (Update: your expected structure is missing two commas).
    #!/usr/bin/perl use warnings; use strict; use JSON; my $struct = { time => time, id => int rand 65536, }; while (<DATA>) { chomp; my ($key, $value, $format, $version) = split /,/; push @{ $struct->{data} }, { key => $key, value => $value, format => $format, version => $version, }; } my $jsonizer = JSON->new->pretty; print $jsonizer->encode($struct); __DATA__ first,1,1.5.6,5.4 two,2,1.4.6,5.4 five,5,1.5.9,5.1

    You might need to use JSON::XS or Cpanel::JSON::XS if speed is important to you.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      what does data in  $struct->{data} stands for?
      Also Is it possible to use without pretty? I understood Its difficult for the DataBase to read it.
      Thank you for the fast answer
        "data" is the key you used on line 4 of your JSON. In other words, $struct is a hash reference, $struct->{data} is the value corresponding to the "data" key in the referenced hash. It contains an array reference to which the code pushes the subhashes.

        To get the output without ->pretty, just delete ->pretty from the code.

        How is a database involved? What error are you getting? How do you interact with it?

        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
        what does data in $struct->{data} stands for?

        $struct is a hash reference. data is an autovivified key in the referenced hash. (Update: The  -> arrow operator is needed because  $struct is a reference.) Each new hash reference built from each line of input read from an input file or from the  __DATA__ handle (as in the example code) is push-ed to the value of this key.

        Also Is it possible to use without pretty?

        Did you try it? What happened? (Update: And what does the documentation say?)


        Give a man a fish:  <%-{-{-{-<

Re: Create JSON file in specific format
by wjw (Priest) on Apr 25, 2018 at 04:20 UTC

    Following is an example that does what you are talking about, but uses a query from a MySQL DB for a data source instead of a text file. You mention a database but do not specify what DB you are interested in. There is a web page involved which requests the data which is why the CGI module is included, but that is probably not all that interesting to you. The code works as is which is why I post it the way I do minus a few mods such as passwords being obfuscated. I do used the pretty print, but as previously pointed out by others, one can simply turn it off as shown in the documentation.

    While reading a csv file line by line has no real faults, you can also use a module such as DBD::CSV to treat your csv file just like a regular DB with a good set of SQL statements available to use.

    That may be more than you want, or not. Just thought I would toss it out there in case you are interested in or familiar with SQL. Hope some of this is useful to you....

    #!/usr/bin/perl use Modern::Perl qw(2014); use DBD::mysql; use JSON; use CGI::Carp qw(fatalsToBrowser); my @output; my $cgi = CGI->new; my %params = $cgi->Vars; my $params = \%params; my $json = JSON::XS->new(); $|=1; my $q; if ( ! $params->{'start'}) { $q = qq(select * from exhibit where timestamp > subtime(now(), + "24:0:0.0")); $params->{'interval'} = qq(24:0:0.0); } else { $q = qq(select * from exhibit where timestamp >= '$params{'sta +rt'}' and timestamp <= '$params{'end'}'); } my $db = "breakins"; my $host = "localhost"; #"192.168.0.3"; my $user = "xxx"; my $password = "xxxxxxx"; my $dsn = "DBI:mysql:database=$db;host=$host;port=3306"; my $dbh = DBI->connect($dsn, $user, $password ); # the query to the db is determined above using times passed in by the + web page # in this case, I do a bit of modification to individual rows as they +are put in @output so data is in the specific json format required # also add fields to each row which I don't want to store in the datab +ase as they are redundant. my $sth = $dbh->prepare($q); $sth->execute; while ( my $row = $sth->fetchrow_hashref ){ $row->{'label'} = $row->{'timestamp'} . "-" . $row->{'IP +'}; $row->{'display'} = 'true'; $row->{'recurring'} = 'false'; $row->{'color'} = 'FFEEBB'; $row->{'timestamp'} = iso_time($row->{'timestamp'}); push @output, $row; } $dbh->disconnect; # Make sure that the resultant JSON will print out all nice and pretty $json->pretty(1); #or condensed if this is set to 0 # $prettyJSON will contain the text string which is the Oh-So-Pretty v +ersion of $jsonStructure my $prettyJson = $json->encode(\@output); print $cgi->header(-type=>'application/json', -rel=>'exhibit-data'); print qq({\n"items":); print $prettyJson; print qq(}\n); sub getdate { my $ts = shift; my $arg = shift; my ($date, $time) = split('T', $ts); if ($arg eq 'd') { return $date; } else { return $time; } } sub iso_time { my $t = shift; my @tp = split(' ', $t); my $ret = join('T', @tp); return $ret; } =pod startDate: Date in which your activity starts. If it is a recurring ev +ent, then all dates within the startDate/endDate range may display th +e event. If your event is not recurring, make the startDate and endDa +te the same. endDate: The ending date for your event. startTime: The time your event starts. endTime: The time your event ends. display: Whether the calendar will display your event. Enter either "t +rue" or "false". label: The label for your event. This will be displayed on the calenda +r within each box for each event. description: Your event description. recurring: If your event is recurring, list the days of the week it oc +curs on. Use "M", "T", "W", "R", "F", "S", and "Sn" for "Monday", "Tu +esday", "Wednesday", "Thursday", "Friday", "Saturday", and "Sunday", +respectively. color: The background color of your event. Please enter a hex, rgb, or + color name. =cut

    ...the majority is always wrong, and always the last to know about it...

    A solution is nothing more than a clearly stated problem...

Re: Create JSON file in specific format
by Anonymous Monk on Apr 25, 2018 at 12:35 UTC
    The key point is that use JSON provides you with a Perl object that can both encode and decode ... "pretty" or not. To accomplish your task, you first construct the desired Perl data structure – in this case, an array of hashes – then you use that object to convert the structure into a JSON string. Or, vice-versa. In any case, the JSON object is treated as a black-box which is known to work correctly. You do not "build" the JSON string yourself. Simply trust that the object will do the right thing – because it will.