printing json from perl is incorrect - json

Im trying to print out in json format info that I have gotten, I think if I show what I have that will better explain everything.
foreach ...{
printer($versions);
}
sub printer
{
foreach ...{
my $results = id_cards();
my $toJsonResult = JSON::to_json($results);
print $toJsonResult;
}
}
sub id_cards
{
my $returnData = [];
for($x=1;$y < $vehicle->{'ROWS'};$x++ )
{
my $data;
$data->{year} = $vehicle->{$x}->{'YEAR'}; #there is more $data->repetativeness but not important to get the point
push(#$returnData,$data);
$y++
}
return $returnData;
}
the json that is printed:
[{"year":"2004"},{"year":"2004"}][{"year":"2002"},{"year":"2000"},{"year":"1994"}][{"year":"2004"},{"year":"1955"}][{"year":"2004"},{"year":"1955"}]
This is very close to what I want but there is no separation of the json "objects"? (not sure what the term is) but it makes it not valid json. What can I do to put the years grouped accordingly but in valid json.

You are printing multiple JSON texts in a loop. Each time you go around the loop, you print a new JSON text.
You should build your data structure in the loop, and then convert the whole thing to JSON afterwards.
e.g.
sub printer {
my #data;
foreach ...{
push(#data, id_cards());
}
print JSON::to_json(\#data);
}

You already have the right idea in the id_cards sub:
sub some_function {
my $return_array = [];
foreach (...) {
push(#$return_array, $some_result);
}
return $return_array;
}
Do the same thing in printer:
sub printer {
my $return_array = [];
# for ...
return $return_array;
}
Then in the outermost foreach at the top of the file do the same:
my $results = [];
foreach (...) {
push(#$results,printer($versions));
}
print JSON.to_json($results);
Only print once, at the last minute. JSON expects a fully formed data structure. If you don't give it everything then you can't expect it to know how to format it properly.
Of course, at this point, the function printer doesn't print anything. So it is misnamed. I would change its name to card_collection or something.

You're effectively doing the following:
my $result = [ { year => 2002 }, { year => 2003 } ];
my $toJsonResult = JSON::to_json($results);
print $toJsonResult; # [{"year":"2002"},{"year":2003"}]
my $result = [ { year => 2004 }, { year => 2005 } ];
my $toJsonResult = JSON::to_json($results);
print $toJsonResult; # [{"year":"2004"},{"year":2005"}]
my $result = [ { year => 2006 }, { year => 2007 } ];
my $toJsonResult = JSON::to_json($results);
print $toJsonResult; # [{"year":"2006"},{"year":2007"}]
That creates a new JSON document for each result, and jams them all together on STDOUT.
You want to create one document that's an array of all your results, so you need to place your all your results in an array.
my #results
my $result = [ { year => 2002 }, { year => 2003 } ];
push $results, $result;
my $result = [ { year => 2004 }, { year => 2005 } ];
push $results, $result;
my $result = [ { year => 2006 }, { year => 2007 } ];
push $results, $result;
my $toJsonResult = JSON::to_json(\#results);
print $toJsonResult; # [[{"year":"2002"},{"year":"2003"}],
# [{"year":"2004"},{"year":"2005"}],
# [{"year":"2006"},{"year":"2007"}]]

Related

Api Response and Json laravel format

I'm using Laravel 5.7. and GuzzleHttp 6.0 to get API response
from endpoint
I'm passing query data from Blade form to this function.
public static function prhmulti($multisearch, $start ,$end)
{ $city = $multisearch['city'];
$client = new Client([
'base_uri' => 'https://avoindata.prh.fi/tr/',
'query' => [
'totalResults' => 'true',
'maxResults' => '1000',
'registeredOffice'=> $city,
'companyForm'=>'OY',
'companyRegistrationFrom'=>$start,
'companyRegistrationTo'=>$end,
],
'defaults'=>[
'timeout' => 2.0,
'cookies' => true,
'headers' => [
'content-type' => 'application/json',
'User-Agent' =>"GuzzleHttp/Laravel-App-5.7, Copyright MikroMike"
]]]);
$res = $client->request('GET','v1');
$ResData = json_decode($res->getBody()->getContents());
dd ($ResData) gives all data from API response.
But I am not able to return JSON back to other function
return $this->multisave($ResData);
public static function multisave (data $ResData)
This will parse JSON and
{
foreach ($data->results as $company) {
$name = $company->name;
$Addr = $company->addresses;
$businessId = $company->businessId;
$companyForm = $company->companyForm;
$registrationDate = $company->registrationDate;
foreach ($company->addresses as $Addr) {
$city = $Addr->city;
$postcode = $Addr->postCode;
$street = $Addr->street;
}
}
save data to Mysql.
$NewCompany = new Company();
$NewCompany = Company::updateOrCreate($array,[
[ 'vat_id', $businessId],
[ 'name', $name],
[ 'form',$companyForm],
[ 'street', $Addr],
[ 'postcode', $postcode],
[ 'city', $city],
[ 'regdate', $registrationDate],
]);
}
IF Parse part and Save part is inside same function code works ok(save only one company),
but I need to separate them because later on it's easier to maintain.
Error which I am getting to return $ResData
" Using $this when not in object context"
Information is in JSON array.
Also foreach part save ONLY one company ?
foreach ($data->results as $company) {
$name = $company->name;
$Addr = $company->addresses;
$businessId = $company->businessId;
$companyForm = $company->companyForm;
$registrationDate = $company->registrationDate;
foreach ($company->addresses as $Addr) {
$city = $Addr->city;
$postcode = $Addr->postCode;
$street = $Addr->street;
}
So : 1) What is best way to create own function for parse JSON
and other for save data to DB?
2) As foreach loop save only one company data, What is
best way to fix it?
Thanks MikroMike.
Resolved my own question for saving companies to db
First get total number inside Array
use for-loop to make counting
use foreach-loop extract information per single company as object.
$data = json_decode($res->getBody()->getContents());
$total = $data->totalResults;
for ($i = 0; $i < $total; $i++){
$NewCompany = new Company();
foreach ($data->results as $company)
{
$name = $company->name;
$businessId = $company->businessId;
$companyForm = $company->companyForm;
$registrationDate = $company->registrationDate;
$array = [];
Arr::set($array, 'vat_id', $businessId);
Arr::set($array, 'name', $name );
Arr::set($array, 'form', $companyForm);
Arr::set($array, 'regdate', $registrationDate);
$NewCompany = Company::updateOrCreate($array,[
[ 'vat_id', $businessId],
[ 'name', $name],
[ 'form',$companyForm],
[ 'regdate', $registrationDate],
]);
}// END OF MAIN FOREACH
}// END OF For loop
}// END OF FUCNTION
} // END OF CLASS

How to create associative array in Yii2 and convert to JSON?

I am using a calendar in my project and I want to pass data from my Event model to view file in JSON format. I tried following but it didn't work and am not able to display the data properly
$events = Event::find()->where(1)->all();
$data = [];
foreach ($events AS $model){
//Testing
$data['title'] = $time->title;
$data['date'] = $model->start_date;
$data['description'] = $time->description;
}
\Yii::$app->response->format = 'json';
echo \yii\helpers\Json::encode($data);
But it only returns one model in that $data array, the final data should be in following format:
[
{"date": "2013-03-19 17:30:00", "type": "meeting", "title": "Test Last Year" },
{ "date": "2013-03-23 17:30:00", "type": "meeting", "title": "Test Next Year" }
]
When you write this:
\Yii::$app->response->format = 'json';
before rendering data, there is no need to do any additional manipulations for converting array to JSON.
You just need to return (not echo) an array:
return $data;
An array will be automatically transformed to JSON.
Also it's better to use yii\web\Response::FORMAT_JSON constant instead of hardcoded string.
Another way of handling that will be using ContentNegotiator filter which has more options, allows setting of multiple actions, etc. Example for controller:
use yii\web\Response;
...
/**
* #inheritdoc
*/
public function behaviors()
{
return [
[
'class' => 'yii\filters\ContentNegotiator',
'only' => ['view', 'index'], // in a controller
// if in a module, use the following IDs for user actions
// 'only' => ['user/view', 'user/index']
'formats' => [
'application/json' => Response::FORMAT_JSON,
],
],
];
}
It can also be configured for whole application.
Update: If you are using it outside of controller, don't set response format. Using Json helper with encode() method should be enough. But there is also one error in your code, you should create new array element like this:
$data = [];
foreach ($events as $model) {
$data[] = [
'title' => $time->title,
'date' => $model->start_date,
'description' => $time->description,
];
}
You can try like this:
$events = Event::find()->select('title,date,description')->where(1)->all()
yii::$app->response->format = yii\web\Response::FORMAT_JSON; // Change response format on the fly
return $events; // return events it will automatically be converted in JSON because of the response format.
Btw you are overwriting $data variable in foreach loop you should do:
$data = [];
foreach ($events AS $model){
//Make a multidimensional array
$data[] = ['time' => $time->title,'date' => $model->start_date,'description' => $time->description];
}
echo \yii\helpers\Json::encode($data);

Perl string to Json

package Emp;
sub new
{
my $class = shift;
my $self = {
OrderID => shift,
OrderDate => shift,
CustomerID => shift,
ShipName => shift,
Freight => shift,
};
bless $self, $class;
return $self;
}
sub TO_JSON { return { %{ shift() } }; }
package main;
use JSON;
my $JSON = JSON->new->utf8;
$JSON->convert_blessed(1);
$e = new Emp( "10248", "1996-07-04", "WILMK","Vins","10");
$json = $JSON->encode($e);
print "$json\n";
I try to convert my String to JSON by using above example. The output is like below:
{"Freight":"10","OrderDate":"1996-07-04","CustomerID":"WILMK","OrderID":"10248","ShipName":"Vins"}
Where do I change if I wanted my JSON to be like below:
{
"rows":[
{"OrderID":"10248","OrderDate":"1996-07-04","CustomerID":"WILMK","ShipName":"Vins et alcools Chevalier","Freight":"32.3800"},
{"OrderID":"10276","OrderDate":"1996-08-08","CustomerID":"TORTU","ShipName":"Tortuga Restaurante","Freight":"13.8400"},
{"OrderID":"10277","OrderDate":"1996-08-09","CustomerID":"MORGK","ShipName":"Morgenstern Gesundkost","Freight":"125.7700"}
]
}
Any advice or reference links is highly appreciated.
Create the data structure you are looking for, and then call JSON->encode
In your main package, try the following:
use JSON;
my $JSON = JSON->new->utf8;
$JSON->convert_blessed(1);
my $data = { rows => [] };
push #{$data->{rows}}, new Emp( "10248", "1996-07-04", "WILMK","Vins","32");
push #{$data->{rows}}, new Emp( "10276", "1996-08-08", "TORTU","Tortuga","13");
push #{$data->{rows}}, new Emp( "10277", "1996-08-09", "MORGK","Morgenstern","125");
$json = $JSON->encode($data);
print "$json\n";
Output:
{"rows":[{"Freight":"32","OrderDate":"1996-07-04","CustomerID":"WILMK","OrderID":"10248","ShipName":"Vins"},
{"Freight":"13","OrderDate":"1996-08-08","CustomerID":"TORTU","OrderID":"10276","ShipName":"Tortuga"},
{"Freight":"125","OrderDate":"1996-08-09","CustomerID":"MORGK","OrderID":"10277","ShipName":"Morgenstern"}]}

JSON formatting in Perl

I am trying to create a JSON object that lists maps associated to a particular user, but haven't ever worked with nested JSON objects. This is what I want:
{
"success":"list of users maps",
"maps":[
{
"id":"1",
"name":"Home to LE",
"date_created":"1366559121"
},
{
"id":"2",
"name":"Test 1",
"date_created":"1366735066"
}
]
}
with this perl code:
my $maps = [];
for (my $x = 0; $x < $sth->rows; $x++) {
my ($id, $name, $date) = $sth->fetchrow_array();
my $map = qq{{"id":"$id","name":"$name","date_created":"$date"}};
push $maps, $map;
}
my $j = JSON::XS->new->utf8;
my $output = $j->encode({
"success"=>"list of users maps",
"maps"=>$maps
});
But the output I am getting is:
{
"success":"list of users maps",
"maps":[
"{\"id\":\"1\",\"name\":\"Home to LE\",\"date_created\":\"1366559121\"}",
"{\"id\":\"2\",\"name\":\"Test 1\",\"date_created\":\"1366735066\"}"
]
}
So when I process it in my Javascript, the data.maps[x].id is undefined. I am pretty sure that the JSON being output is incorrectly formatted.
Can anyone help me fix it?
It's undefined because what you have at data.maps[x] is not an object, but a string. Since a string has no property called id, you're getting undefined. I'd probably do something like this (if I couldn't change the perl script):
var mapData = JSON.parse(data.maps[x]);
//do stuff with mapData.id
But the better thing to do, is to make sure that it doesn't encode it as a string, but as proper JSON.
This part in your perl script:
my $map = qq{{"id":"$id","name":"$name","date_created":"$date"}};
Is simply making a quoted string out of all that data. Instead, what you want is an actual perl hash that can be translated into a JSON map/associative-array. So try this:
my $map = {
"id" => "$id",
"name" => "$name",
"date_created" => "$date"
};
push $maps, $map;
This way you actually have a perl hash (instead of just a string) that will get translated into proper JSON.
As an example, I wrote some test code:
use strict;
use JSON::XS;
my $maps = [];
push $maps, { id => 1, blah => 2 };
push $maps, { id => 3, blah => 2 };
my $j = JSON::XS->new->utf8->pretty(1);
my $output = $j->encode({
success => "list of blah",
maps => $maps
});
print $output;
When you run this, you get:
{
"success" : "list of blah",
"maps" : [
{
"blah" : 2,
"id" : 1
},
{
"blah" : 2,
"id" : 3
}
]
}

Perl to convert data into JSON format

I have a problem, converting my data into json, and I don't know why.
Here is some Code that works:
#constructor
sub new {
my $class = shift;
my $Titel = shift;
my $Text = shift;
my $Time = localtime;
my $self = {};
$self->{text} = $Text;
$self->{create} = $Time;
$self->{edit} = $Time;
my $json = JSON::XS->new();
open WF, '>> $file' || die "Error : $!";
print WF $json->encode($self)."\n";
close WF;
bless $self, $class;
}
I create an 'object' and save the data in a textfile (via JSON), too.
I have problems, if I try to edit some data:
sub edit {
my $self = shift;
my $Text = shift;
my $ID = shift;
my $Time = localtime;
my $json = JSON::XS->new();
$json->allow_blessed(1);
$self->{text} = $Text; #edit text
$self->{edit} = $Time; # edit date
open INPUT, '< $file' || die "Error : $!";
my #data = <INPUT>;
close(INPUT);
open WF, '> $file' || die "Error : $!";
for (my $Count=0; $Count<=$#data; $Count++){
chomp($data[$Count]);
if($Count == $ID){#if line of data found, who is going to be edited
print WF $json->encode($self)."\n";
}else{
print WF $data[$Count]."\n";
}
}
close WF;
}
What I try to do is to edit just one line in the textfile.. (if you have a better idea, please show me :D)
I see no difference between my procedure in the code shown first and that one....
it just writes "null" back in the textfile...
Any ideas?
I'm no JSON expert, but the encode method is having trouble with a blessed reference. Using an unblessed reference seems like a valid workaround:
if($Count == $ID){#if line of data found, who is going to be edited
print WF $json->encode( {%$self} )."\n";
...
I second the notion (as you have already found) that the problem is the blessed reference, however I offer you another solution (the is Perl after all: TIMTOWTDI). The Acme::Damn module allows you to unbless (i.e. damn) an object. Therefore you should be able to:
print WF $json->encode(damn($self))."\n";
Also I felt I had to share, since the method is so cleverly named.
Following the last mob's suggestion, here is simple example how to serialize blessed references.
package Node;
sub new {
my $class = shift;
bless { #_ }, $class;
}
sub TO_JSON {
my $self = shift;
return { class => 'Node', data => { %$self } };
}
package main;
use JSON;
my $node_hash = {
a => [ 'text1', 'text2' ],
b => [ 'what', 'is', 'this' ],
c => [ Node->new(some => 'data') ],
};
print to_json($node_hash, { convert_blessed => 1 });
However you need to pay attention in decoding. It is possible to use filter_json_single_key_object to implement full round-trip.