How to convert JSON/Dynamic Structure to Map in Haxe? - json

I'm a very new to coding and generally work with a drag and drop editor that is based on Haxe (Stencyl) as a hobby.
I have a JSON file that I would like to convert into a nested map (dictionary). I have tried using the JSON parsing function but it returns an anonymous (dynamic) structure.
How can I either convert the JSON file into a map or convert the Anonymous structure into a map?
Sample of the JSON:
{
"apple": {
"value": 10,
"health": 15,
"tags": [
"fruit",
"fiber",
"sweet"
]
},
"lemon": {
"value": 5,
"health": 10,
"tags": [
"fruit",
"citrus",
"sour"
]
},
"ham": {
"value": 50,
"health": 50,
"tags": [
"salty",
"meat"
]
}
}

Another option would be to use the json2object library, which natively supports Map<String, T>:
import sys.io.File;
import json2object.JsonParser;
class Main {
public static function main() {
var parser = new JsonParser<Data>();
var source = File.getContent("data.json");
var data = parser.fromJson(source, "data.json");
trace(data["apple"].value); // 10
}
}
typedef Data = Map<String, {
var value:Int;
var health:Int;
var tags:Array<String>;
}>
This approach avoids both reflection and Dynamic, which are usually considered bad practice.

You could create Map and fill it via Reflect api:
var parse = haxe.Json.parse(s);
var map:Map<String, StructData> = new Map();
for(field in Reflect.fields(parse))
{
map.set(field, Reflect.field(parse, field));
}
typedef StructData = {
var value:Int;
var health:Int;
var tags:Array<String>;
}
https://try.haxe.org/#DFa77

Take a look at the DynamicAccess abstract here.
Given your sample I've made a quick example here:
import haxe.DynamicAccess;
typedef Food = {
var value:Int;
var health:Int;
var tags:Array<String>;
}
class Test {
static function main() {
var json = {
"apple": {
"value": 10,
"health": 15,
"tags": [
"fruit",
"fiber",
"sweet"
]
},
"lemon": {
"value": 5,
"health": 10,
"tags": [
"fruit",
"citrus",
"sour"
]
},
"ham": {
"value": 50,
"health": 50,
"tags": [
"salty",
"meat"
]
}
};
var foodMap:DynamicAccess<Food> = json;
// Get a single entry
var apple = foodMap.get("apple");
trace(apple.tags.join(", "));
// Loop through names
for (foodName in foodMap.keys()) {
trace(foodName);
trace(foodMap.get(foodName).value);
}
}
}

Related

Google Sheets - Parse JSON string contained in one cell and extract specific values to another cell

I have a sheet where for each row in column Z there is a JSON string recovered from Twitter via TAGS.
The JSON strings in column Z all have a similar structure:
{
"hashtags": [
{
"text": "Negev_Summit",
"indices": [
172,
185
]
}
],
"symbols": [],
"user_mentions": [
{
"screen_name": "JY_LeDrian",
"name": "Jean-Yves Le Drian",
"id": 1055021191,
"id_str": "1055021191",
"indices": [
69,
80
]
}
],
"urls": [],
"media": [
{
"id": 1513588335893258200,
"id_str": "1513588335893258240",
"indices": [
271,
294
],
"media_url": "http://pbs.twimg.com/media/FQFYknkXoAAxgYd.jpg",
"media_url_https": "https://pbs.twimg.com/media/FQFYknkXoAAxgYd.jpg",
"url": "https://twitter.com/yairlapid/status/1513588345468825605",
"display_url": "pic.twitter.com/dA4cBepIh2",
"expanded_url": "https://twitter.com/yairlapid/status/1513588345468825605/photo/1",
"type": "photo",
"sizes": {
"medium": {
"w": 1024,
"h": 576,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 1024,
"h": 576,
"resize": "fit"
},
"small": {
"w": 680,
"h": 383,
"resize": "fit"
}
}
}
]
}
I need to extract specific values for each JSON string in column Z and put them in columns AA, AB and AC (hashtags, user mentions, and URL's).
I've managed to achieve this with a really dirty multiple REGEXREPLACE formula but it doesn't seem logical that there is no way to fo this more efficiently:
=IFERROR("#"&JOIN(" #",SPLIT(REGEXREPLACE(REGEXREPLACE(REGEXREPLACE(REGEXREPLACE(REGEXREPLACE(REGEXEXTRACT(INDIRECT("Y"&ROW()),".*user_mentions\"":\[(.*)\],\""urls.*"),"(,\""indices\"":\[\d+,\d+\])",""),"(,\""id_str\"":\""\d+\"")",""),"(,\""id\"":\d+)",""),"(\{\""screen_name\"":\"")",""),"\"",\""name\"":\""(.){1,50}\""\}",""),",")),"")
Ideally i'm looking for a script which would parse the JSON string and extract 1 or more values from each section of the JSON. For example:
For hashtags (column AA):
=PARSEJSON(Z1, "hashtags")
Result:
#hashtag1 #hashtag2
For user_mentions (column AB):
=PARSEJSON(Z1, "user_mentions/screen_name")
Result:
#username1 #username2
Would appreciate any help sending me in the right direction.
If your main purpose is to only get the values in screen_name I'd modify my script and I'd use =IMPORTJSON(url, "user_mentions/screen_name")
/**
* Imports JSON data to your spreadsheet Ex: IMPORTJSON("http://myapisite.com","city/population")
* #param url URL of your JSON data as string
* #param xpath simplified xpath as string
* #customfunction
*/
function IMPORTJSON(url,xpath){
try{
var res = UrlFetchApp.fetch(url);
var content = res.getContentText();
var json = JSON.parse(content);
var patharray = xpath.split("/");
for(var i=0;i<patharray.length;i++){
json = json[patharray[i]];
}
if(typeof(json) === "undefined"){
return "Node Not Available";
} else if(typeof(json) === "object"){
var tempArr = [];
for(var obj in json){
tempArr.push([obj,json[obj]]);
}
return tempArr;
} else if(typeof(json) !== "object") {
return json;
}
}
catch(err){
return "Error getting data";
}
}
I managed to do it with a different script I found here.
This is the script:
function getData(json, path) {
const obj = JSON.parse(json);
const keys = path.split('.');
let current = obj;
for( key of keys ){
current = current[key];
}
return current;
}
You would then enter in the cell with =getData(Z1, "hashtags")
#Yiddy s answer did not work for me. So i did some modifications to it and came up with this.
function getData(range, path, sheet_name) {
var sprsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sprsheet.getSheetByName(sheet_name);
var string = sheet.getRange(range).getValue();
var json = JSON.parse(string);
const keys = path.split('.');
var current = json;
for (key of keys) {
current = current[key];
}
return current;
}

Mapping data that contains dots in React

I am trying to map the data in React that is coming from the API but I am having problems mapping the object that contains dots for example this: name.en_US.
What is the proper way to map this object and keeping the data structure that I have?
I am getting the date in this format from the API:
{
"user": "User",
"employeeId": "0000",
"businessCustomer": "customer",
"endCustomer": {
"name": "",
"address": "",
"place": ""
},
"device": {
"shipmentIds": "23",
"name.en_US": "wasi",
"name.fi_FI": " masi"
},
"task": {
"time": "2019-02-10T16:55:46.188Z",
"duration": "00:00:24",
"sum": "75€"
}
},
And then I am trying to map it using the following code.
const {
user,
employeeId,
businessCustomer,
endCustomer,
device,
task
} = task;
const{
endCustomerName,
address,
place
} = endCustomer;
const {
shipmentIds,
names
} = device;
const{
en_US,
fi_FI
} = names;
const {
time,
duration,
summa
} = task;
const data = {
"user": "User",
"employeeId": "0000",
"businessCustomer": "customer",
"endCustomer": {
"name": "",
"address": "",
"place": ""
},
"device": {
"shipmentIds": "23",
"name.en_US": "wasi",
"name.fi_FI": " masi"
},
"task": {
"time": "2019-02-10T16:55:46.188Z",
"duration": "00:00:24",
"sum": "75€"
}
};
const { device } = data;
const {
shipmentIds,
'name.en_US': name_en_US,
'name.fi_FI': name_fi_FI
} = device;
const nameUS = device['name.en_US'];
console.log(name_en_US, nameUS);
Use [ ] notation like, device['name.en_US'] .
You can destructure your propery as #Vishnu mentioned, or you could also destructure it by providing a valid key name
const {
shipmentIds,
'name.en_US': name_en_US,
'name.fi_FI': name_fi_FI
} = device;
And then you could access your variable with name_en_US.

Getting inventory contexts of Steam users

A stack overflow answer explains how to retrieve a user's public inventory
http://steamcommunity.com/profiles/<PROFILEID>/inventory/json/<APPID>/<CONTEXTID>
I read that context ID must be set as 2 to find items for most games, but this is not always the case. Is there any official API to find a user's inventory contexts? steamapis.com already has a paid API which performs this task:
{
"steamID": {
"universe": 1,
"type": 1,
"instance": 1,
"accountid": 78261062
},
"name": "PEPZ",
"onlineState": "online",
"stateMessage": "Online",
"privacyState": "public",
"visibilityState": "3",
"avatarHash": "5b702b331ddeb928225ad562a3e729aecd191b9a",
"vacBanned": false,
"tradeBanState": "None",
"isLimitedAccount": false,
"customURL": "pepzwee",
"memberSince": "2011-02-21T22:00:00.000Z",
"location": "Estonia",
"realName": "SteamApis.com Developer",
"summary": "",
"groups": [
{
"universe": 1,
"type": 7,
"instance": 0,
"accountid": 28077004
},
...
],
"primaryGroup": {
"universe": 1,
"type": 7,
"instance": 0,
"accountid": 28077004
},
"contexts": {
"440": {
"appid": 440,
"name": "Team Fortress 2",
"icon": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/440/e3f595a92552da3d664ad00277fad2107345f743.jpg",
"link": "http://steamcommunity.com/app/440",
"asset_count": 11,
"inventory_logo": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/440/e613d1d46de26ea755105b898cc8830d305353f3.png",
"trade_permissions": "FULL",
"load_failed": 0,
"rgContexts": {
"2": {
"asset_count": 11,
"id": "2",
"name": "Backpack"
}
}
},
...
}
}
Where "rgContexts" contains inventory context for each game.
I found out with some inspect element work, that there is a script tag available with the exact information you need. This is an example of my profile:
var g_rgWalletInfo = {"success":false};
var g_bInventoryIsInModalDialog = false;
var g_bIsInMarketplace = false;
UserYou.SetSteamId( '76561199033382814' );
var g_rgAppContextData = {"753":{"appid":753,"name":"Steam","icon":"https:\/\/cdn.cloudflare.steamstatic.com\/steamcommunity\/public\/images\/apps\/753\/135dc1ac1cd9763dfc8ad52f4e880d2ac058a36c.jpg","link":"https:\/\/steamcommunity.com\/app\/753","asset_count":303,"inventory_logo":"https:\/\/cdn.cloudflare.steamstatic.com\/steamcommunity\/public\/images\/apps\/753\/db8ca9e130b7b37685ab2229bf5a288aefc3f0fa.png","trade_permissions":"FULL","load_failed":0,"store_vetted":"1","rgContexts":{"6":{"asset_count":303,"id":"6","name":"Community"}}},"730":{"appid":730,"name":"Counter-Strike: Global Offensive","icon":"https:\/\/cdn.cloudflare.steamstatic.com\/steamcommunity\/public\/images\/apps\/730\/69f7ebe2735c366c65c0b33dae00e12dc40edbe4.jpg","link":"https:\/\/steamcommunity.com\/app\/730","asset_count":61,"inventory_logo":"https:\/\/cdn.cloudflare.steamstatic.com\/steamcommunity\/public\/images\/apps\/730\/3ab6e87a04994b900881f694284a75150e640536.png","trade_permissions":"FULL","load_failed":0,"store_vetted":"1","rgContexts":{"2":{"asset_count":61,"id":"2","name":"Backpack"}}}};
var g_strInventoryLoadURL = 'https://steamcommunity.com/id/stoplookingatmyid/inventory/json/';
$J( function() {
UserYou.LoadContexts( g_rgAppContextData );
} );
$J( function() {
var bHasPendingGifts = false;
InitInventoryPage( bHasPendingGifts, -1, false );
});
var g_bInClient = false;
var g_bInChinaRealm = false;
var g_bViewingOwnProfile = false;
var g_bMarketAllowed = false;
var g_strLanguage = 'english';
var g_strCountryCode = "US";
var g_strProfileURL = 'https://steamcommunity.com/id/stoplookingatmyid';
Some of this data is junk, but g_rgAppContextData is exactly what you need in JSON format, and it just needs to be parsed if your programming language of choice. In this example, 753 is the app id of Steam, with 6 being the context id, and 730 is CSGO'S app id, with 2 as the context id. with This data won't be present if the user has a private steam inventory.

How can i get an array of images from a collection of nested objects with Lodash?

{
"shop": {
"homebackground": "http://padmenu.s3.amazonaws.com/15/11/2014/05/08/2ec2ff61-d6a0-11e3-8857-10ddb1e6e201.jpg",
"name": {
"tr": "My Shop"
},
"menus": [{
"name": {
"en": "Menu"
},
"children": [{
"name": {
"en_US": "Category"
},
"images": [
"http://www.progressivedental-ellenlimdds.com/wp-content/uploads/2014/06/red-wine.jpg"
],
"children": [{
"name": {
"en_US": "Item"
},
"images": [
"http://res.cloudinary.com/finedine/image/upload/c_fill,g_center,h_600/v1435916818/WIne-Bottle_uz03a0.jpg",
"http://media.riepenau.com/wines/17973_b.jpg",
"http://lorempixel.com/400/400/food/3",
"http://lorempixel.com/400/400/food/4",
"http://lorempixel.com/400/400/food/5",
"http://lorempixel.com/400/400/food/6",
"http://lorempixel.com/400/400/food/7"
]
}]
}]
}]
}
}
I want to select all the "images" arrays from shop's "children" objects.
How can i do this by using Lodash library?
The output should be an array of consists of image urls:
["url1","url2","url3"]
The easiest approach to solve this problem is by plucking through children and their descendants recursively. The important points are in the getImages() function; wherein it flattens all children arrays in one level, pluck each image arrays and compact all items to remove undefined values(caused by children with no images), and then flattening the images array and readied for concatenation. The stopping point of the recursion is when there are no images for the current children, returning an empty array. If images are found, then we recursively concatenate all potential descendant images. As to how we get the descendants, we use the same chaining sequence that we used in getting the images array but with children as the plucking key.
DEMO
function getImages(children) {
var images = _(children).flatten().pluck('images').compact().flatten().value();
if(_.isEmpty(images)) {
return [];
}
var descendants = _(children).flatten().pluck('children').compact().flatten().value();
return images.concat(getImages(descendants));
}
function getShopImages(data) {
var children = _.pluck(data.shop.menus, 'children');
return getImages(children);
}
console.log(getShopImages(data));
Pseudo Code
You can solve this with a little bit of recursion:
Grab the children list.
Extract all the images from the children list with pluck.
Repeat step 1 with all descendants.
Concat all results and flatten.
Core Code
function deepExtract(collection, childKey, property) {
var exists = _.negate(_.isEmpty);
var children = _.chain(collection).pluck(childKey).filter(exists).flatten();
if (_.isEmpty(children.value())) {
return [];
}
var images = children.pluck(property).value();
var descendantImages = deepExtract(children.value(), childKey, property);
return _.flatten(images.concat(descendantImages));
};
var tree = _.chain(data).get('shop.menus').value();
var images = deepExtract(tree, 'children', 'images');
Demo
var data = {
"shop": {
"homebackground": "http://padmenu.s3.amazonaws.com/15/11/2014/05/08/2ec2ff61-d6a0-11e3-8857-10ddb1e6e201.jpg",
"name": {
"tr": "My Shop"
},
"menus": [{
"name": {
"en": "Menu"
},
"children": [{
"name": {
"en_US": "Category"
},
"images": [
"http://www.progressivedental-ellenlimdds.com/wp-content/uploads/2014/06/red-wine.jpg"
],
"children": [{
"name": {
"en_US": "Item"
},
"images": [
"http://res.cloudinary.com/finedine/image/upload/c_fill,g_center,h_600/v1435916818/WIne-Bottle_uz03a0.jpg",
"http://media.riepenau.com/wines/17973_b.jpg",
"http://lorempixel.com/400/400/food/3",
"http://lorempixel.com/400/400/food/4",
"http://lorempixel.com/400/400/food/5",
"http://lorempixel.com/400/400/food/6",
"http://lorempixel.com/400/400/food/7"
]
}]
}]
}]
}
};
function deepExtract(collection, childKey, property) {
var exists = _.negate(_.isEmpty);
var children = _.chain(collection).pluck(childKey).filter(exists).flatten();
if (_.isEmpty(children.value())) {
return [];
}
var images = children.pluck(property).value();
var descendantImages = deepExtract(children.value(), childKey, property);
return _.flatten(images.concat(descendantImages));
};
var tree = _.chain(data).get('shop.menus').value();
log(deepExtract(tree, 'children', 'images'));
// Helper method to output to screen
function log(value) {
document.getElementById("output").innerHTML += JSON.stringify(value, null, 2) + "\n"
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>
<pre id="output"></pre>
I found an alternative solution to my question here:
var children = _(shop.menus[0].children)
.thru(function(coll) {
return _.union(coll, _.pluck(coll, 'children'));
})
.flatten();
var images = _.chain(children).pluck('images').flattenDeep().compact().uniq().value();
The output "images" is an image array.

Access nested JSON object in AngularJS controller

I am new to AngularJS and trying to create a $scope for tracks for later usage
data.json (sample):
[
{
"album": "Album name",
"tracks": [
{
"id": "1",
"title": "songtitle1",
"lyric": "lyrics1"
},
{
"id": "2",
"title": "songtitle2",
"lyric": "lyrics2"
}
]
}
]
Controller
app.controller('lyricsCtrl', function($scope, $http) {
$http.get('data.json')
.then(function(result) {
$scope.albums = result.data;
$scope.tracks = result.data.tracks;
console.log($scope.tracks); //Undefined...
});
});
Why is $scope.tracks undefined?
If your json file is as is:
[
{
"album": "Album name",
"tracks": [
{
"id": "1",
"title": "songtitle1",
"lyric": "lyrics1"
},
{
"id": "2",
"title": "songtitle2",
"lyric": "lyrics2"
}
]
}
]
We have a response of:
data: Array[1]
0: Object
album: "Album name"
tracks: Array[2]
Since data is returned as an array you would handle like any other javascript array and access by index, so you could do a loop or if you know only 1 result is going to be returned you could use the zero index:
$http.get('data.json').then(function(result) {
console.log(result);
// Assign variables
$scope.album = result.data[0].album;
$scope.tracks = result.data[0].tracks;
for (var i = 0, l = $scope.tracks.length; i < l; i++) {
console.log($scope.tracks[i].title);
}
});
result.data is an array,So you must have to use index to access its child like:-
$scope.tracks = result.data[0].tracks;
It should be result.data[0].tracks as data is an array
$scope.tracks = result.data[0].tracks;