Extract data from complex JSON in Flutter - json

I'm working in extract data from more complex JSON with unknown structure, its structure changes with operation ,
JSON sample link :http://afs-i.com/json.json
Kindly find my code here : http://afs-i.com/main.dart
Thanks in advance
Update:
I extracted the data using PHP code, you can find result here: http://afs-i.com/json.php
Kindly this is my PHP code:
$arraycars=array();
$y=json_decode($x);
// echo "<pre>";
// var_dump($y->tree[0]->children);
foreach ($y->tree[0]->children as $f) {
if(isset($f->vid)){
global $arraycars;
$arraycars[]=$f;
} elseif(isset($f->children)){
if(sizeof($f->children) > 0){
coolectcars($f->children);
}
}
}
function coolectcars($array){
// var_dump($array);
foreach ($array as $f) {
if(isset($f->vid)){
global $arraycars;
$arraycars[]=$f;
} elseif(isset($f->children)){
if(sizeof($f->children) > 0){
coolectcars($f->children);
}
}
}
}
echo json_encode($arraycars);
Update:2
I have problem now with null error for this code:
The error:
I/flutter ( 4264): NoSuchMethodError: The method 'forEach' was called on
null.
I/flutter ( 4264): Receiver: null
I/flutter ( 4264): Tried calling: forEach(Closure: (Children) => Null)
The code:
List<Children> cars = [];
Queue numQ = new Queue();
numQ.addAll(parsed["tree"][0]["children"]);
Iterator i = numQ.iterator;
while (i.moveNext()) {
// print("ddddddd ${i.current}");
if (i.current.containsKey("vid")) {
cars.add(new Children(
i.current['vid'], i.current['protocol'], i.current['datetime'],
i.current['gpss']));
} else {
Queue numQ = new Queue();
if (i.current["children"] != null) {
numQ.addAll(i.current["children"]);
// iterate(numQ);
List<Children> carse=[];
carse = iterate(numQ);
carse.forEach((data){
cars.add(data);
}) ;
}
}
}
cars.forEach((data) {
print(data.toString());
});
List<Children> iterate(Queue numQ) {
List<Children> cars=new List<Children>();
Iterator i = numQ.iterator;
while (i.moveNext()) {
print("ddddddd ${i.current}");
if (i.current.containsKey("vid")) {
cars.add(new Children(
i.current['vid'], i.current['protocol'], i.current['datetime'],
i.current['gpss']));
} else {
if (i.current["children"] != null) {
Queue numQ = new Queue();
numQ.addAll(i.current["children"]);
List<Children> carse=[];
carse = iterate(numQ);
carse.forEach((data){
cars.add(data);
}) ;
}
}
return cars;
}
}

I prefer using built_value to do json deserialization/ serialization. It's more elegant. You don't need to write down fromJson by yourself. built_value will generate deserializers / serializer for you. You can check built_value's github or this and this articles.

A good place for convert JSON to dart here
hats to reddit url
just copy your json into the textbox and generate, it will auto generate for you.
With this, you can call fromJson and feed it the json, then you can also get auto complete for it
eg: usage
final response =
await http.get('http://afs-i.com/json.json');
if (response.statusCode == 200) {
final Autogenerated respJson = Autogenerated.fromJson(json.decode(response.body));
print(respJson.tree[0].userId);
}

insert this import 'dart:convert';
into your widget file at top.
lets say you have your json in
var response
then
var jsonDecoded= json.decode(response);
now you can get name and user_id like this:
var user_id= jsonDecoded["tree"][0]["user_id"];
var name = jsonDecoded["tree"][0]["name"];
NOTE : I get these values from the first object (0 index). If you want values for each object , you can loop to get it.

The final answer i reach:
final parsed = json.decode(response.body);
List<Children> cars = [];
Queue numQ = new Queue();
numQ.addAll(parsed["tree"][0]["children"]);
Iterator i = numQ.iterator;
while (i.moveNext()) {
if (i.current.containsKey("vid")) {
cars.add(new Children(
i.current['vid'],
i.current['datetime'],
));
} else {
Queue numQ = new Queue();
if (i.current["children"].toString() != "[]") {
numQ.addAll(i.current["children"]);
List<Children> carse = [];
carse = iterate(numQ);
carse.forEach((data) {
cars.add(data);
});
}
}
}
List<Children> iterate(Queue numQ) {
List<Children> cars = new List<Children>();
Iterator i = numQ.iterator;
while (i.moveNext()) {
if (i.current.containsKey("vid")) {
if (i.current.containsKey("vid")) {
cars.add(new Children(
i.current['vid'],
i.current['datetime'],
));
}
} else {
if (i.current["children"].toString() != "[]") {
Queue numQ = new Queue();
if (i.current["children"].toString() != "[]") {
numQ.addAll(i.current["children"]);
List<Children> carse = [];
carse = iterate(numQ);
carse.forEach((data) {
cars.add(data);
});
}
}
}
return cars;
}

Related

How to retrieve entire Logger output?

I have large sets of data (mainly arrays and objects with many elements) and I am trying to log out the entire result to check for bugs. However, in some cases it says "Logging output too large. Truncating output." Where can I see the output in its entirety? I am working with Map Objects and trying to debug why my calculations don't match Google's output.
Logger.log is limited to the number of lines that it can contain. However you can make your own logger and save it to a text file.
var Log = null;
function testLogger() {
try {
Log = new LogFile("testLogFile");
test1();
test2();
throw "done"
}
catch(err) {
Log.log(err);
Log.save();
}
}
function test1() {
Log.log("in test1");
}
function test2() {
Log.log("in test2");
}
class LogFile {
constructor (name) {
if( name === undefined ) name = "_LogFile"
this.name = name;
this.text = [];
}
log(text) {
this.text.push(text);
}
save() {
try {
let text = "";
this.text.forEach( line => text = text.concat(line,"\n") );
let files = DriveApp.getFilesByName(this.name);
let file = null;
if( files.hasNext() ) {
file = files.next();
file.setContent(text);
}
else {
DriveApp.createFile(this.name,text);
}
}
catch(err) {
Logger.log(err);
}
}
}
The text file is shown below.

Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<Model>'

I am trying to parse Json data that I get from an online API but get the error mentioned in the title. I looked at similar questions but could not find a solution.
Here is the relevant code:
class Model {
final double a;
final double b;
final String s;
Model._({this.a, this.b, this.s});
factory Model.fromJson(Map<String, dynamic> json) {
return new Model._(
a: json['a'],
b: json['b'],
s: json['s'],
);
}
}
void fetchPairValue() async {
final response = await http.get('https://api.1forge.com/quotes?pairs=USD/TRY,EUR/USD,EUR/TRY,CAD/TRY,GBP/TRY,AUD/TRY,JPY/TRY,CHF/TRY,AED/TRY,USD/QAR,USD/BGN,DKK/TRY,USD/SAR,USD/CNY,USD/RUB,NOK/TRY,SEK/TRY'
'&api_key=KatWbQa9sDFmYQ25LmtAMlGau5xKSWIe');
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
List<Model> list = json.decode(response.body).map((data) => Model.fromJson(data))
.toList();
setState(() {
currencyPair[0][1] = round_to_4(list[0].b).toString();
currencyPair[0][2] = round_to_4(list[0].a).toString();
for (int i = 1; i < currencyPair.length; i++) {
if(list[i].s.startsWith('USD'))
{
currencyPair[i][1] = round_to_4(list[i].b/list[1].b).toString();
currencyPair[i][2] = round_to_4(list[i].a/list[1].a).toString();
}
else {
currencyPair[i][1] = round_to_4(list[i].b).toString();
currencyPair[i][2] = round_to_4(list[i].a).toString();
}
}
});
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
Sample Json Data:
[{"p":1.21856,"a":1.22201,"b":1.2151,"s":"EUR/USD","t":1608934265255},{"p":7.5575,"a":7.5625,"b":7.5525,"s":"USD/TRY","t":1608908143931},{"p":9.26299,"a":9.27256,"b":9.25342,"s":"EUR/TRY","t":1608879625018},{"p":6.037513,"a":6.039437,"b":6.035589,"s":"CAD/TRY","t":1608933871214},{"p":10.297348,"a":10.316695,"b":10.278,"s":"GBP/TRY","t":1608879629130},{"p":5.7738,"a":5.7885,"b":5.7591,"s":"AUD/TRY","t":1608879564069},{"p":0.07303697,"a":0.07308529,"b":0.07298864,"s":"JPY/TRY","t":1608908143937},{"p":8.529457,"a":8.538269,"b":8.520645,"s":"CHF/TRY","t":1608879624835},{"p":2.057672,"a":2.059033,"b":2.056311,"s":"AED/TRY","t":1608908143934},{"p":3.6413,"a":3.642,"b":3.6405,"s":"USD/QAR","t":1608847204796},{"p":1.6069188,"a":1.61497,"b":1.5988675,"s":"USD/BGN","t":1608861813327},{"p":1.2452666,"a":1.2465531,"b":1.24398,"s":"DKK/TRY","t":1608879625024},{"p":3.752353,"a":3.755106,"b":3.7496,"s":"USD/SAR","t":1608879629251},{"p":6.5418,"a":6.5428,"b":6.5408,"s":"USD/CNY","t":1608909993197},{"p":74.06,"a":74.095,"b":74.025,"s":"USD/RUB","t":1608930021562},{"p":0.87736,"a":0.878167,"b":0.876553,"s":"NOK/TRY","t":1608847205092},{"p":0.917155,"a":0.918032,"b":0.916278,"s":"SEK/TRY","t":1608847203927}]
How to fix? Thanks.
You need to add the generic type to the map function:
List<Model> list = json
.decode(response)
.map<Model>((data) => Model.fromJson(data))
.toList();

Laravel modify collection value with another value of another collection

I have a json file like this,
{
"unique_id_001":{
"price_1":264000,
"price_2":2178000,
"price_3":3168000,
"price_6":1089000,
"price_7":3168000
},
"unique_id_002":{
"price_1":264000,
"price_2":2178000,
"price_3":3168000,
"price_6":1089000,
"price_7":3168000
},
"unique_id_003":{
"price_1":264000,
"price_2":2178000,
"price_3":3168000,
"price_6":1089000,
"price_7":3168000
}
}
I convert it to collection and want to set those price_x to another collection.
public static function getOldPrices()
{
$storagePath = storage_path(self::PATH);
$file = File::get($storagePath);
$data = json_decode($file, true);
$collection = \App\Price::hydrate($data);
$oldPrices = $collection->flatten();
return $oldPrices;
}
public static function all()
{
$prices = \App\Price::all();
$old_prices = self::getOldPrices();
foreach ($prices as $price) {
foreach ($old_prices as $old_price) { // is there another way so I can remove this loop?
if ($price->id === $old_price->id) {
$price->price_1 = $old_price->price_1;
$price->price_2 = $old_price->price_2;
$price->price_3 = $old_price->price_3;
$price->price_6 = $old_price->price_6;
$price->price_7 = $old_price->price_7;
}
}
}
return $prices;
}
This code is working and could change the value of each price in $prices. But I wonder if there is other ways, because I used two foreach loop in this code, and I think it is not good.
I got another way using map()
Here is my updated code
$prices = $prices->map(function ($price) use ($oldPrices) {
if ($oldPrice = $oldPrices->firstWhere('id', $price->id)) {
$price->price_1 = $oldPrice->price_1;
$price->price_2 = $oldPrice->price_2;
$price->price_3 = $oldPrice->price_3;
$price->price_6 = $oldPrice->price_6;
$price->price_7 = $oldPrice->price_7;
}
return $price;
});

Angularjs ajax request in Symfony2 and Doctrine json response with relationships

I am trying to work with Symfony2, Doctrine and Angujarjs. There is no problem with Symfony2 or Doctrine but I have issues using an ajax request with angularjs. Either it doesn't load anything and I did make a mistake while loading the json (json comes from Symfony and its working) or if it's working, but the json doesn't contain any of the relationship's data.
So, what's the correct way to
A: create a response for angularjs with relationship data (such as articles and categories)
B: load the requested json into an angularjs variable
Here is my controller.js
var app = angular.module("MyApp", []) .config(['$interpolateProvider', function ($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
}]);
app.filter('offset', function() {
return function(input, start) {
start = parseInt(start, 10);
return input.slice(start);
};
});
app.filter('htmlToPlaintext', function() {
return function(text) {
return String(text).replace(/<[^>]+>/gm, '');
};
});
app.controller("PaginationCtrl", function($scope, $http) {
$scope.articlesPerPage = 8;
$scope.currentPage = 0;
function htmlToPlaintext(text) {
return String(text).replace(/<[^>]+>/gm, '');
}
// this should load the json from '/admin/jsonallarticles' into the articles variable
$http.get('/admin/jsonallarticles').success(function(data) {
$scope.articles = data;
});
$scope.range = function() {
var rangeSize = 5;
var ret = [];
var start;
start = $scope.currentPage;
if ( start > $scope.pageCount()-rangeSize ) {
start = $scope.pageCount()-rangeSize+1;
}
for (var i=start; i<start+rangeSize; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function() {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.prevPageDisabled = function() {
return $scope.currentPage === 0 ? "disabled" : "";
};
$scope.pageCount = function() {
return Math.ceil($scope.articles.length/$scope.articlesPerPage)-1;
};
$scope.nextPage = function() {
if ($scope.currentPage < $scope.pageCount()) {
$scope.currentPage++;
}
};
$scope.nextPageDisabled = function() {
return $scope.currentPage === $scope.pageCount() ? "disabled" : "";
};
$scope.setPage = function(n) {
$scope.currentPage = n;
};
});
This is my symfony2 function
public function jsonallarticlesAction() {
$articles = $this->getDoctrine()
->getRepository('AcmeBlogBundle:Articles');
if ( !$articles ) {
throw $this->createNotFoundException(
'Keine Beiträge gefunden!');
}
$queryArticles = $articles->createQueryBuilder('a')
->where('a.status = :status')
->setParameter('status', 0)
->orderBy('a.createdDate', 'DESC')
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);;
$articles = array_values($queryArticles);
$response = new Response();
$response->setContent(json_encode($articles));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
EDITED CONTROLLER
I tried using the serializer which comes with Symfony
$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new GetSetMethodNormalizer());
$serializer = new Serializer($normalizers, $encoders);
$articles = $this->getDoctrine()
->getRepository('AcmeBlogBundle:Articles')
->findAll();
if ( !$articles ) {
throw $this->createNotFoundException(
'Keine Artikel gefunden!');
}
$serializer->serialize($articles, 'json');
return new Response(json_encode($json));
But I receive an error:
A circular reference has been detected (configured limit: 1).
For work with Angular.js you must write Rest API. For this you can use https://github.com/FriendsOfSymfony/FOSRestBundle
And for serialize your entities with needed data use http://jmsyst.com/bundles/JMSSerializerBundle
It compatible with FOSRestBundle.
As example of use those bundles you can look one our project https://github.com/stfalcon-studio/lost-and-found
I ran into the same issue and it was due to the fact that my Entity was related back to the same entity from my second entity on a different field. I just simply created this function in my Entity:
public function removeRelationsThatCauseCircularError()
{
$this->companyEvents = NULL;
}
And run the function before going through the serializer.

kendo treeview with new data source

Ok, so I have this situation here:
A CSHTML view with a kendo tree in it:
#(Html.Kendo().TreeView()
.Name("treeview")
.DataTextField("Name")
.DataSource(d => d.Read(r => r.Action("WorkedHours", "TaskManager")))
.Events(e => e.Select("onSelect"))
)
to the right of that there is a kendo grid. and above the tree there is a (kendo) dropdown list to select a user.
this is the controller method called by the tree:
public JsonResult WorkedHours(uint? id)
{
DocObjectArray docObjects = null;
if (id == null)
{
// get root elements
var loggedInUserRef = OmanagerUtils.GetInstance().LoggedInUser;
if (loggedInUserRef != null && loggedInUserRef.GetObject() != null && loggedInUserRef.GetObject().SubObjects != null)
{
for (int i = 0; i < loggedInUserRef.GetObject().SubObjects.GetLength(); i++)
{
var item = loggedInUserRef.GetObject().SubObjects.GetAt(i);
if (item.ToString() == TaskManagerConstants.UserWorkHours)
{
docObjects = item.TreeSubObjects;
break;
}
}
}
}
else
{
// get sub objects of a root object
var rootObj = new DocObjectRef((int)id);
docObjects = rootObj.GetObject().TreeSubObjects;
}
var returnDocObjects = new List<OmanagerItem>();
for (int i = 0; i < docObjects.GetLength(); i++)
{
var item = docObjects.GetAt(i);
var hasChildren = true;
if (item.TreeSubObjects == null)
{
hasChildren = false;
}
else
{
if (item.TreeSubObjects.GetLength() == 0)
{
hasChildren = false;
}
}
var listItem = new OmanagerItem
{
hasChildren = hasChildren,
id = item.GetOID(),
Name = item.ToString()
};
returnDocObjects.Add(listItem);
}
return Json(returnDocObjects, JsonRequestBehavior.AllowGet);
}
now, the problem is that i have to be able to select a user from the dropdown list and refresh the tree with this new data.
$("#employee").kendoDropDownList({
change: function () {
var postdata = {
id:$("#employee").val()
}
$.ajax({
url: "TaskManager/WorkedHours",
cache: false,
type: "POST",
data: postdata,
success: function (data) {
$("#treeview").data("kendoTreeView").setDataSource(data);
},
});
}
});
the problem is what do i do with this data? because my attempt did not really work.
many thanks.
You can use OutputCache attribute on WorkedHours action:
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
public JsonResult WorkedHours(uint? id)
{
// rest of method
}
It helped in my case :)
Maybe this little snippet is of any help to you.
Similar to your code in the change event of my dropdown I'm calling a function that will change the request data of my TreeView DataSource.
After changing it, it calls the read() handler of the datasource so it re-reads the data:
function loadTreeViewData() {
var employee = $('#employee').getKendoDropDownList().dataItem();
WorkedHoursDataSource.transport.options.read.data = {Employee_Id:employee.id};
WorkedHoursDataSource.read();
}