JSON formatting in Perl - json

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
}
]
}

Related

how to insert json to mysql database with codeigniter

I have html table with value like this :
i have convert the value on table to JSON object with jquery plugin tabletoJSON like this :
[{
harga_jual : "47025",
id_buku : "1",
judul_buku : "perempuan dam hak warisnya",
jumlah : "1",
subtotal : "47025"
},
{
harga_jual : "49500",
id_buku : "2",
judul_buku : "Keajaiban Operasi Plastik Korea Selatan",
jumlah : "2",
subtotal : "99000"
}]
I want when i click checkout button, it will insert the json data into mysql with codeigniter, how i write the code on my model and controller?
here my table structure :
id_buku : int
jumlah : double
subtotal :double
big thanks.
Send an object with value of your data(as JSON) to your Controller. e.g (with JQuery):
$.post('your_action_url', {sendData: JSON.stringify(yourData)}, function(res) {
console.log(res);
}, "json");
Then in your controller, you can get the Data with this CI method:
$data = json_decode($this->input->post('sendData'));
and if the $data is an Array of objects and you want to filter the $data, you can loop the $data then call the save method in your model
$this->db->trans_begin();
foreach($data as $row) {
$filter_data = array(
"id_buku" => $row->id_buku,
"jumlah" => $row->jumlah,
"subtotal" => $row->subtotal
);
//Call the save method
$this->your_model_alias->save_as_new($filter_data);
}
if ($this->db->trans_status() === FALSE) {
$this->db->trans_rollback();
echo json_encode("Failed to Save Data");
} else {
$this->db->trans_commit();
echo json_encode("Success!");
}
Consider to use a transaction to store a lot of data at once. This is necessary to avoid things that are not desirable.
your Model's save method should be like this :
public function save_as_new($data) {
$this->db->insert('your_table_name', $data);
}

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

JSON.net parsing of dynamic JSON

I have JSON that looks like this:
{
"status": {
"code": 0,
"message": "OK"
},
"data": {
"_idtype": "cusip",
"_id": "00768Y883",
"api": {
"_name": "PortfolioBreakdownsRaw",
"PortfolioDate": "2015-10-12",
"GlobalBondSuperSectorLongSalePositionBreakdown": [
{
"Name": "Municipal",
"Value": "0.57842"
},
{
"Name": "Corporate",
"Value": "1.79649"
},
{
"Name": "Securitized",
"Value": "5.29493"
},
{
"Name": "Cash & Equivalents",
"Value": "166.20776"
}
],
"GlobalBondSuperSectorShortSalePositionBreakdown": [
{
"Name": "Government",
"Value": "0.90557"
}
]
}
}
}
I am able to get the api portion of the response easily:
var jObject = JObject.Parse(json);
var api = jObject["data"]["api"];
From here, I don't what if any arrays will be included in the response. The ultimate goal will be to create a parser that will be able to get the array names (GlobalBondSuperSectorShortSalePositionBreakdown) and as many rows of key-value pairs that it may contain, without first knowing the names such as (GlobalBondSuperSectorShortSalePositionBreakdown) beforehand.
I can't seem to find a good way to loop through the object, determine there are arrays at the api level and then iterate through those to get the values.
Any help would be appreciated.
Here's an example. In this code, the api variable holds a JObject, so we can iterate over its properties. From there, we look at the Type of each property value to see if it is an array or not. If it is, then we can iterate over that array to get the JObjects within it, and extract the Name and Value values that we expect to find there. Does this help?
var jObject = JObject.Parse(json);
var api = jObject["data"]["api"];
foreach (JProperty prop in api.Children<JProperty>())
{
JToken value = prop.Value;
if (value.Type == JTokenType.Array)
{
Console.WriteLine(prop.Name + ": ");
foreach (JObject jo in value.Children<JObject>())
{
Console.WriteLine(" " + jo["Name"] + ": " + jo["Value"]);
}
}
else
{
Console.WriteLine(prop.Name + ": " + value);
}
}
Output:
_name: PortfolioBreakdownsRaw
PortfolioDate: 2015-10-12
GlobalBondSuperSectorLongSalePositionBreakdown:
Municipal: 0.57842
Corporate: 1.79649
Securitized: 5.29493
Cash & Equivalents: 166.20776
GlobalBondSuperSectorShortSalePositionBreakdown:
Government: 0.90557
Fiddle: https://dotnetfiddle.net/XyoXQy
With Linq you can play pretty nice with Json.net:
Here is an easily readable version of the chunk of code that will create two dictionaries out of the JArray properties under the api element:
var api = jObject["data"]["api"];
var arrays = api.Cast<JProperty>().Where(o => o.Value.Type == JTokenType.Array).Select(token => token.Value).ToArray();
var dictionaries = new List<Dictionary<string, string>>();
foreach (var array in arrays)
{
var dictionary = array.ToDictionary(token => token["Name"].Value<string>(), token => token["Value"].Value<string>());
dictionaries.Add(dictionary);
}
alternative:
The same thing, but a shorter, more compact version :
var api = jObject["data"]["api"];
var dictionaries = api
.Cast<JProperty>()
.Where(o => o.Value.Type == JTokenType.Array)
.Select(token => token.Value)
.Select(array => array.ToDictionary(token => token["Name"].Value<string>(), token => token["Value"].Value<string>()));

encoding json with no quote around numerical values

I have a perl code snippet
use JSON::XS;
$a = {"john" => "123", "mary" => "456"};
print encode_json($a),"\n";
The output is
{"john":"123","mary":"456"}
Wonder if there is an option to cause encode_json function (from JSON::XS module) to encode it so that the values (123, 456) are not surrounded by double-quote. i.e., like
{"john":123,"mary":456}
Unfortunately I can't change the hash in $a because it's passed to me from another function. Wonder if there is any trick on encode_json().
Thanks!
You probably need to preprocess the data yourself, prior to JSON serialization.
This solution uses Data::Leaf::Walker to traverse an arbitrary structure, converting strings to numbers.
use JSON;
use Data::Leaf::Walker;
use Scalar::Util qw();
my $a = {"john" => "123",
"mary" => ["456","aa"],
"fred" => "bb",
"nested" => {"Q" => undef, "A" => 42},
};
my $walker = Data::Leaf::Walker->new( $a );
while (my ( $key_path, $value ) = $walker->each ) {
$walker->store($key_path, $value + 0)
if Scalar::Util::looks_like_number $value;
};
print to_json($a);
Output: {"john":123,"nested":{"A":42,"Q":null},"mary":[456,"aa"],"fred":"bb"}
You shouldn't use JSON::XS directly, just JSON will already load JSON::XS if available.
A scalar in Perl is tagged whether it is a string or a number, and here you're providing strings. Remove the quotes from your numbers, and they should show up unquoted as JSON already does that automatically.
If you're reading strings (from say a database) then you can coerce the strings to numbers like this:
{ john => 0+$john, mary => 0+$mary }
Update, here's a recursive replacement:
#!/usr/bin/env perl
use JSON;
use Modern::Perl;
use Scalar::Util qw( looks_like_number );
my $structure = {
john => "123",
mary => 456,
deeper => {
lucy => "35zz",
names => [
"john",
"123",
456,
],
},
};
sub make_numbers_recursively {
my ( $data ) = shift;
if ( ref $data eq 'HASH' ) {
# Replace hash values with recurisvely updated values
map { $data->{ $_ } = make_numbers_recursively( $data->{ $_ } ) } keys %$data;
} elsif ( ref $data eq 'ARRAY' ) {
# Replace each array value with recursively processed result
map { $_ = make_numbers_recursively( $_ ) } #$data;
} else {
$data += 0 if looks_like_number( $data );
}
return $data;
}
my $json = JSON->new->pretty;
say $json->encode( $structure );
make_numbers_recursively( $structure );
say $json->encode( $structure );
This outputs:
{
"mary" : 456,
"deeper" : {
"names" : [
"john",
"123",
456
],
"lucy" : "35zz"
},
"john" : "123"
}
{
"mary" : 456,
"deeper" : {
"names" : [
"john",
123,
456
],
"lucy" : "35zz"
},
"john" : 123
}
Beware that it modifies the structure in-place, so if you need the original data for anything you might want to Clone or Data::Clone it first.

JSON is reordering returned list

I have some jQuery that will change the contents of a select box depending upon the value of another select box (it uses AJAX). The PHP is returning the array how I want (sorted by TypeDescriptionData.name), but the list is getting re-ordered somewhere in the JS. Any ideas?
PHP Call:
public function get_descriptions_by_type($typeId) {
$this->autoRender = false;
$this->loadModel('TypeDescriptionData');
$data = array();
$this->TypeDescriptionData->contain();
$descriptions = $this->TypeDescriptionData->find('list', array('conditions' => array('type_data_id' => $typeId), 'order' => 'name ASC'));
if(isset($descriptions) && is_array($descriptions)) {
foreach($descriptions as $x => $y) {
$data[$x] = $y;
}
}
echo json_encode($data);
}
Here's the JSON right after the json_encode php call above:
{
"1":"FD 50",
"9":"Hypercom T4210",
"2":"Hypercom T7P",
"8":"Hypercom T7Plus",
"10":"Nurit 2085",
"11":"Nurit 8400",
"12":"Nurit 8400 Lite",
"17":"Other Terminal",
"13":"Verifone Tranz 330",
"14":"Verifone Tranz 380",
"15":"Verifone Vx510",
"16":"Verifone Vx510 LE"
}
Here's the JS:
$('#TypeType').change(function() {
$('#TypeDescription').find('option').remove().end();
$.ajax({
url:'/TypeData/get_descriptions_by_type/' + $(this).val(),
type:'POST',
dataType: 'json',
success: function( json ) {
console.log(JSON.stringify(json));
$.each(json, function(i, value) {
$('#TypeDescription').prepend($('<option>').text(value).attr('value', i));
});
}
});
});
And here's the JSON if I add "console.log(JSON.stringify(json));" immediately after the "success: function( json ) {" in the JS above:
{
"1":"FD 50",
"2":"Hypercom T7P",
"8":"Hypercom T7Plus",
"9":"Hypercom T4210",
"10":"Nurit 2085",
"11":"Nurit 8400",
"12":"Nurit 8400 Lite",
"13":"Verifone Tranz 330",
"14":"Verifone Tranz 380",
"15":"Verifone Vx510",
"16":"Verifone Vx510 LE",
"17":"Other Terminal"
}
A json object is an associative array, so the two objects are actually equivalent. Basically the computer doesn't remember the order, just key/value pairs. If order really matters to you then you need to use some other kind of structure. For example you could embed an array:
{
"beaches" : [
{"key" : "1", "value" : "FD 50"},
{"key" : "2", "value" : "Hypercom T7P"},
{"key" : "8", "value" : "Hypercom T7Plus"}
]
}