I am working with MongoDB and so far I have been able to loop through the following JSON correctly with the ability to manipulate the data to display.
controller
$json = '[{
"T": {
"HD": {
"HD01": "1",
"HD06": "20201006033942",
"HD08": "3736803"
}
}
},
{
"T": {
"HD": {
"HD01": "1",
"HD06": "20201006035419",
"HD08": "3736803"
}
}
}]'
$keysToRemove = ['HD01', 'HD06'];
$data = collect(json_decode($data, true))
->flatten(2)
->map(function ($array, $key) use ($keysToRemove) {
foreach ($keysToRemove as $key) {
if (array_key_exists($key, $array)) {
unset($array[$key]);
}
}
return $array;
});
return view('dashboard.book.index', [
'data' => $data
]);
Blade
<table>
<tr>
#foreach ($data->first() as $key => $value)
<th>{{ $key }}</th>
#endforeach
</tr>
#foreach ($data as $items)
<tr>
#foreach ($items as $key => $value)
<td>{{ $value }}</td>
#endforeach
</tr>
#endforeach
</table>
result
Table
Now, now I must go through another one that has an array inside it, and which is made up as follows:
controller
$data = '[{
"T": {
"SIEL" : {
"SIE" : [
{
"sequenceNumber" : 0,
"itemId" : "3010",
"itemDescription" : "BAN VACCINE COSTELLET",
"unitAmount" : 29950,
"quantity" : 1,405,
"subTotalAmount" : 42080,
"discountAmount" : 0,
"totalAmount" : 42080
},
{
"sequenceNumber" : 1,
"itemId" : "1010",
"itemDescription" : "CROLETA COOKIE",
"unitAmount" : 4800,
"quantity" : 0.605,
"subTotalAmount" : 2904,
"discountAmount" : 0,
"totalAmount" : 2904
}
]
}
}
}]';
How do I go through it following the logic of the first one, to obtain the 'SIE' data?
It is a similar principle to your previous question. Decode your JSON to an associative array, convert to a collection, flatten it and work with the result.
$sieData = collect(json_decode($data, true))->flatten(3)->collapse();
return view('view.blade.php', compact('sieData'));
The value of sieData is an array of associated arrays. You already have how to loop over such a structure in the example code you provided in your question.
Related
I have three sample JSON file that I need to loop through. I was able to do two of them already, but the third one is missing. The idea is to go through it using the same logic as the first two.
Example 1 (Sales header)
Controller
$data1 = '[{
"T": {
"HD": {
"HD01": "1",
"HD06": "20201006033942",
"HD08": "3736803"
}
}
},
{
"T": {
"HD": {
"HD01": "2",
"HD06": "20201006035419",
"HD08": "7523658"
}
}
}]';
$json = json_decode($data1, true);
$head = collect($json)->map(function ($value) {
return $value["T"]["HD"];
});
return view('dashboard.book.index', [
'head' => $head
]);
Blade
<table class="table">
<tr>
<td> HD01</td>
<td> HD02</td>
<td> HD03</td>
<td> HD04</td>
<td> HD05</td>
<td> HD06</td>
</tr>
#foreach ($head as $value)
<tr>
<td>{{ $value['HD01'] }}</td>
<td>{{ $value['HD02'] }}</td>
<td>{{ $value['HD03'] }}</td>
<td>{{ $value['HD04'] }}</td>
<td>{{ $value['HD05'] }}</td>
<td>{{ $value['HD06'] }}</td>
</tr>
#endforeach
</table>
Result
Header
Example 2 (Detail of sale)
Controller
$data2 = '[{
"T": {
"SIEL" : {
"SIE" : [
{
"sequenceNumber" : 0,
"itemId" : "3010",
"itemDescription" : "BAN VACCINE COSTELLET",
"unitAmount" : 29950,
"quantity" : 1,405,
"subTotalAmount" : 42080,
"discountAmount" : 0,
"totalAmount" : 42080
},
{
"sequenceNumber" : 1,
"itemId" : "1010",
"itemDescription" : "CROLETA COOKIE",
"unitAmount" : 4800,
"quantity" : 0.605,
"subTotalAmount" : 2904,
"discountAmount" : 0,
"totalAmount" : 2904
}
]
}
}
},
{
"T": {
"SIEL" : {
"SIE" : [
{
"sequenceNumber" : 0,
"itemId" : "3010",
"itemDescription" : "BAN VACCINE COSTELLET",
"unitAmount" : 29950,
"quantity" : 1,405,
"subTotalAmount" : 42080,
"discountAmount" : 0,
"totalAmount" : 42080
},
{
"sequenceNumber" : 1,
"itemId" : "1010",
"itemDescription" : "CROLETA COOKIE",
"unitAmount" : 4800,
"quantity" : 0.605,
"subTotalAmount" : 2904,
"discountAmount" : 0,
"totalAmount" : 2904
}
]
}
}
}
]';
$json = json_decode($data2, true);
$details = collect($json)->map(function ($value) {
return $value["T"]["SIEL"]["SIE"];
});
return view('dashboard.book.index', [
'details' => $details
]);
Blade
<table class="table">
<tr>
<td> sequenceNumber</td>
<td> itemId</td>
<td> itemDescription</td>
<td> unitAmount</td>
<td> quantity</td>
<td> subTotalAmount</td>
<td> discountAmount </td>
<td> totalAmount </td>
</tr>
#foreach ($details as $items)
#foreach ($items as $key => $value)
<tr>
<td>{{ $value['sequenceNumber'] }}</td>
<td>{{ $value['itemId'] }}</td>
<td>{{ $value['itemDescription'] }}</td>
<td>{{ $value['unitAmount'] }}</td>
<td>{{ $value['quantity'] }}</td>
<td>{{ $value['subTotalAmount'] }}</td>
<td>{{ $value['discountAmount'] }}</td>
<td>{{ $value['totalAmount'] }}</td>
</tr>
#endforeach
#endforeach
</table>
Result
Details
Example 3 (Header more detail)
$data3 = '[
{
"T":{
"HD":{
"HD01":"1",
"HD02":"20201007",
"HD03":"1001",
"HD04":"15",
"HD05":140,
"HD06":"20201007062511",
"HD07":"",
"HD08":"3514401",
"HD09":"PYG",
"HD10":"PYG",
"HD11":"00000 A000005",
"HD12":"",
"HD13":"",
"HD14":"",
"HD15":"",
"HD16":"",
"HD17":"Insufficient Funds",
"HD18":"",
"HD19":"",
"HD20":"",
"HD21":0,
"HD22":"ICAE",
"HD23":false,
"HD24":false,
"HD26":0
},
"SIEL":{
"SIE":[
{
"sequenceNumber":0,
"itemId":"1159",
"itemDescription":"BREAD FOR PANCHO",
"unitAmount":3500,
"quantity":0.001,
"subTotalAmount":4,
"discountAmount":0,
"totalAmount":4
},
{
"sequenceNumber":1,
"itemId":"2098",
"itemDescription":"HAPPY DAY CAKE",
"unitAmount":28950,
"quantity":0.001,
"subTotalAmount":29,
"discountAmount":0,
"totalAmount":29
}
]
}
}
},
{
"T":{
"HD":{
"HD01":"1",
"HD02":"20201007",
"HD03":"1001",
"HD04":"15",
"HD05":141,
"HD06":"20201007063358",
"HD07":"",
"HD08":"3514401",
"HD09":"PYG",
"HD10":"PYG",
"HD11":"0010580000125",
"HD12":"",
"HD13":"",
"HD14":"",
"HD15":"",
"HD16":"",
"HD17":"",
"HD18":"",
"HD19":"",
"HD20":"",
"HD21":16100,
"HD22":"ICAE",
"HD23":false,
"HD24":false,
"HD26":-47
},
"SIEL":{
"SIE":[
{
"sequenceNumber":0,
"itemId":"1110",
"itemDescription":"STICK WITHOUT ANISE",
"unitAmount":9100,
"quantity":1.115,
"subTotalAmount":10147,
"discountAmount":0,
"totalAmount":10147
},
{
"sequenceNumber":1,
"itemId":"7841503001513",
"itemDescription":"TRIPACK CRACKER CLASS",
"unitAmount":6000,
"quantity":1,
"subTotalAmount":6000,
"discountAmount":0,
"totalAmount":6000
}
}
]
}
}
}
]';
$json = json_decode($data3, true);
$tickets = collect($json)->map(function ($value) {
return ????
});
So, I don't know how to put it in the return so that the data is sent and go through it as a single combined table
Example of how it should be:
Table
One possible solution would be to obtain all the keys from the JSON string and store those as a separate variable, then do something similar for the actual data.
So for example, to obtain all the keys from your JSON you could do the following:
$keys =
collect(json_decode($data)[0]->T->HD)
->merge(collect(json_decode($data)[0]->T->SIEL->SIE[0]))
->keys();
What this does is produce an array of just the JSON keys you're interested in making iterating over the keys nice and simple.
#foreach ($keys as $key)
{{ $key }}
#endforeach
As for your data, it would be a similar process but instead we're focusing on the values of the JSON rather than the keys.
$data = collect(json_decode($data))->map(function ($element) {
return collect($element->T->HD)->merge(collect(['SIE' => $element->T->SIEL->SIE]));
});
This results in a (somewhat flattened) collection of your data with all HD prefixed keys at the top level of each collection element and a sub collection of SIE elements.
[
"HD01" => 1,
"HD02" => 2,
...
"SIE" => [
[
"sequenceNumber":0,
"itemId":"1110",
"itemDescription":"STICK WITHOUT ANISE",
...
],
...
]
]
From here it should be a straight forward process of iterating over the data in your blade view to ouput it.
A functional example here.
I am using kartik DepDropdown widget. When I choose the region it must load all the cities from it in the particular dropdown (e.g. the one with id city_id).
In the chrome network tab I can see that the action returns the expected result json format of all the cities
{
"output": {
"40": "Велико Търново",
"41": "Горна Оряховица",
"42": "Елена",
"43": "Златарица",
"44": "Лясковец",
"45": "Павликени",
"46": "Полски Тръмбеш",
"47": "Свищов",
"48": "Стражица",
"49": "Сухиндол"
},
"selected": ""
}
But they doesn't load in the #city_id dropdown. My view looks like:
<div class="col-sm-6">
<?= $form->field($model, 'region_id')->dropDownList(Region::getAllRegions(), ['id' => 'region-dd', 'prompt'=> ' - ' . Yii::t('app', 'Region') . ' - ']); ?>
</div>
<div class="col-sm-6">
<?= $form->field($model, 'city_id')->widget(DepDrop::classname(), [
'options'=>[
'id'=>'city-id'
],
'pluginOptions'=>[
'allowClear' => true,
'depends' => ['region-dd'],
'url' => Url::to(['/system-information/load-cities'])
]
]); ?>
</div>
My controller:
public function actionLoadCities()
{
$out = [];
if (isset($_POST['depdrop_parents'])) {
$parents = $_POST['depdrop_parents'];
if ($parents != null) {
$region_id = $parents[0];
$out = City::getAllCities($region_id);
echo Json::encode(['output'=>$out, 'selected'=>'']);
return;
}
}
echo Json::encode(['output'=>'', 'selected'=>'']);
}
Thank you in advance!
You have to provide the name=>value pairs of the id and the text to be assigned for a single option, if you look into the DOCS you will see that you have to return the array like below
[
'out'=>[
['id'=>'<city-id>', 'name'=>'<city-name>'],
['id'=>'<city-id>', 'name'=>'<city-name>']
],
'selected'=>'<city-id>'
]
which means that the id will be provided with the index id and the text for the dropdown will be provided with the index name, and looking at the response you have provided your method getAllCities is returning the array like below
[
'id'=>'name',
'id'=>'name',
]
you didn't add the method City::getAllCities($region_id); which is returning the $out array but on the very basic level as per documentation it should look like below,
Note: Change the table and column names respectively, I assume you have the id and name columns for the cities, if you have any other column name for the city name like city_name then you must create the alias name for the city_name field in the query.
public function getAllCities($region_id){
$query = new \yii\db\Query;
$query->select('id, name')
->from('{{%city}}')
->where(['=', 'region_id', $region_id])
->limit(20);
$command = $query->createCommand();
return $command->queryAll();
}
This will return an array like below.
Array
(
[0] => Array
(
[id] => 40
[name] => Велико Търново
)
[1] => Array
(
[id] => 41
[name] => Горна Оряховица
)
[2] => Array
(
[id] => 42
[name] => Елена
)
[3] => Array
(
[id] => 43
[name] => Златарица
)
)
which will be encoded as JSON like below
[
{
"id": "40",
"name": "Велико Търново"
},
{
"id": "41",
"name": "Горна Оряховица"
},
{
"id": "42",
"name": "Елена"
},
{
"id": "43",
"name": "Златарица"
}
]
and eventually when encode by the line
echo Json::encode(['output'=>$out, 'selected'=>'']);
it will return
{
"output": [
{
"id": "40",
"name": "Велико Търново"
},
{
"id": "41",
"name": "Горна Оряховица"
},
{
"id": "42",
"name": "Елена"
},
{
"id": "43",
"name": "Златарица"
}
],
"selected": ""
}
Hope this helps.
I am trying to write a perl code to parse multiple JSON messages. The perl code that I have written only parses the values if the JSON file contains only one json message. But it fails when there are multiple messages in that file. It throws error: "Undefined subroutine &Carp::shortmess_heavy". The JSON file is in the following format:
{
"/test/test1/test2/test3/supertest4" : [],
"/test/test1/test2/test3/supertest2" : [
{
"tag1" : "",
"tag2" : true,
"tag3" : [
{
"status" : "TRUE",
"name" : "DEF",
"age" : "28",
"sex" : "f"
},
{
"status" : "FALSE",
"name" : "PQR",
"age" : "39",
"sex" : "f"
}
],
"tag4" : "FAILED",
"tag5" : "/test/test1/test2/test3/supertest2/test02",
"tag6" : ""
}
],
"/test/test1/test2/test3/supertest1" : [
{
"tag1" : "",
"tag2" : false,
"tag3" : [
{
"status" : "TRUE",
"name" : "ABC",
"age" : "21",
"sex" : "m"
},
{
"status" : "FALSE",
"name" : "XYZ",
"age" : "34",
"sex" : "f"
}
],
"tag4" : "PASSED",
"tag5" : "/test/test1/test2/test3/supertest1/test01",
"tag6" : ""
}
],
"/test/test1/test2/test3/supertest6" : []
}
My perl code to parse a single JSON message:
use strict;
use warnings;
use Data::Dumper;
use JSON;
use JSON qw( decode_json );
my $json_file = "tmp1.json";
my $json;
open (my $fh, '<', $json_file) or die "can not open file $json_file";
{ local $/; $json = <$fh>; }
close($fh);
my $decoded = decode_json($json);
print "TAG4 = " . $decoded->{'tag4'} . "\n";
print "TAg5 = " . $decoded->{'tag5'} . "\n";
my #tag3 = #{ $decoded->{'tag3'} };
foreach my $tg3 ( #tag3 ) {
print "Name = ". $tg3->{"name"} . "\n";
print "Status = ". $tg3->{"status"} . "\n";
print "Age = ". $tg3->{"age"} . "\n";
}
To parse multiple JSON objects, use JSON::XS/Cpanel::JSON::XS's incremental parsing.
my $json = '{"foo":"bar"} ["baz"] true 1.23';
my #results = JSON::XS->new->allow_nonref->incr_parse($json);
use Data::Dumper;
print Dumper \#results;
Output:
$VAR1 = [
{
'foo' => 'bar'
},
[
'baz'
],
bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
'1.23'
];
So, i'm making a programm fetching the data as hash from PostgreSQL, which uses a couple JSONs as parameter file and output datafile respectively. And i had some problem with fetching what it shouldn't fetch. Here's parameter json:
{
"queries": [
{
"table_name" : "t1",
"subqueries": [
{
"query_id" : "t1_1",
"query": [
.....some sql query
],
"to_hash" : {
"target_by" : "type_id", // key to index by
"keys" : [
{
"source" : "name", // key in hash from db
"target" : "name" // key in new hash
},
{
"source" : "r",
"target" : "r"
}
]
}
},
{
"query_id" : "t1_2",
"query": [
.....some sql query
],
"to_hash" : {
"target_by" : "type_id",
"keys" : [
{
"source" : "m",
"target" : "m"
}
]
}
}
]
}
]
}
....and here's a perl subroutine:
my $fname = "query_params.json";
my $q_data_raw;
{
local $/;
open(my $fh, "<:encoding(UTF-8)", $fname) or oops("$fname: $!");
$q_data_raw = <$fh>;
close($fh);
}
my $q_data = JSON->new->utf8->decode($q_data_raw);
my %result;
sub blabla {
my $data = shift;
my($tab, $i) = ($data->{table_name}, 0);
if ($data->{subqueries} ne "false"){
my %res_hash;
my #res_arr;
my $q_id;
foreach my $sq (#{$data->{subqueries}}){
my $query = "";
$q_id = $sq->{query_id};
print "\n";
print "$q_id\n";
for(#{$sq->{query}}){
$query .= "$_\n";
}
my $t_by = $sq->{to_hash}{target_by};
my $q_hash = $db_connection->prepare($query);
$q_hash->execute() or die( "Unable to get: " . $db_connection->errstr);
while(my $res = $q_hash->fetchrow_hashref()) {
# print Dumper $res; #print #1
for(#{$sq->{to_hash}->{keys}}){
# print "\nkey:\t" . $_->{target} . "\nvalue:\t".$res->{$_->{source}}; #print #2
$res_hash{$q_id}{$res->{$t_by}}{$_->{target}} = $res->{$_->{source}};
}
$res_hash{$q_id}{$res->{$t_by}}{__id} = $res->{$t_by};
# print Dumper %res_hash; #print #3
}
push #res_arr, $res_hash{$q_id};
# print Dumper $res_hash{$q_id}; #print #4
# print Dumper #res_arr; print #5
$result{$tab}{$q_id} = \#res_arr;
$q_hash->finish();
}
}
}
for (#{$q_data->{queries}}){ // hash from parameter json
blabla($_);
}
my $json = JSON->new->pretty->encode(\%result);
# to json file
....and there's what i get:
{
"t1" : {
"t1_1" : [
{
//type_id_1_* - from first query
"type_id_1_1" : {
"r" : "4746",
"__id" : "type_id_1_1",
"name" : "blablabla"
},
"type_id_1_2" : {
"r" : "7338",
"__id" : "type_id_1_2",
"name" : "nbmnbcxv"
},
....
},
{
//type_id_2_* - from second query
"type_id_2_1" : {
"m" : "6",
"__id" : "type_id_2_1"
},
"type_id_2_2" : {
"m" : "3",
"__id" : "type_id_2_2"
},
............
}
],
"t1_2" : [
{
"type_id_1_1" : {
"r" : "4746",
"__id" : "type_id_1_1",
"name" : "blablabla"
},
"type_id_1_2" : {
"r" : "7338",
"__id" : "type_id_1_2",
"name" : "nbmnbcxv"
},
....
},
{
"type_id_2_1" : {
"m" : "6",
"__id" : "type_id_2_1"
},
"type_id_2_2" : {
"m" : "3",
"__id" : "type_id_2_2"
},
............
}
]
}
}
Somehow, it fetches the queries from other subqueries, what i don't want. And loop seems to be ok, probably. What am i doing wrong?
Well, seems like i initialized #res_arr and #res_hash in wrong level - gotta be in foreach. The output is kinda what i need. At least i don't have duplicates.
Gotta be sleep more X(
....
my $q_id;
foreach my $sq (#{$data->{subqueries}}){
my %res_hash;
my #res_arr;
my $query = "";
$q_id = $sq->{query_id};
print "\n";
print "$q_id\n";
..........
}
I'm trying to get the value of username and id from the following output.
{
"listusersresponse": {
"count": 1,
"user": [
{
"id": "f01e8ea4-2da5-11e4-a846-726c7bbb864f",
"username": "admin",
"firstname": "admin",
"lastname": "test",
"created": "2014-08-26T20:52:24-0400",
"state": "enabled",
"account": "admin",
"accounttype": 1,
"domainid": "c091153a-2da5-11e4-a846-726c7bbb864f",
"accountid": "f01e7c02-2da5-11e4-a846-726c7bbb864f",
"iscallerchilddomain": false,
"isdefault": true
}
]
}
}
This is what I have tried
$url = file_get_contents("http://URL/client/&response=json");
$data = json_decode($url);
var_dump($data);
foreach ($data as $value) {
echo $value->count;
}
For this works and I get 1
However when trying to access "username"
foreach ($data as $value) {
echo $value->user->username;
}
I get the following error: Notice: Trying to get property of non-object in "filename"
User is an array.
foreach ($data as $value) {
echo $value->user[0]->username;
}
Not sure how your json looks with several users, It must be like this then I guess:
foreach ($data as $value) {
foreach ($value->user as $user) {
echo $user->username;
}
}