How to parse all JSON strings in a JavaScript object - javascript

I have 1 JavaScript object like this:
result = {
"status": "success",
"message": "Get successful!",
"data": {
"name":"Hello world",
"school": {
"name":"LHP",
"address":"HCM"
},
"class": "[{\"text\":\"Math\",\"code\":\"math124\"},{\"text\":\"Libra\",\"code\":\"libra124\"}]",
"student": "{\"time_range\":{\"type\":\"select\",\"text\":\"Today\",\"value\":[{\"code\":\"in_today\",\"text\":\"In Today\"}]}}"
}
}
So I have to parse class and student separately:
result.data.class = JSON.parse(result.data.class);
result.data.student = JSON.parse(result.data.student);
Is there other way to parse the whole result variable or make this step shorter/better?
Thanks

You could loop through the data property's children and parse them.
for (var i = 0; i < Object.keys(result.data).length; i++) {
try {
result.data[Object.keys(result.data)[i]] = JSON.parse(result.data[Object.keys(result.data)[i]]);
} catch (error) {} // it's already JSON
}
But I'd only do that if you're sure you'll only ever have to deal with stringified JSON in the data property of your object.

Related

Cannot read property of length undefined

I'm using a dexi.io robot to automate extraction from permit databases. The robot will accept custom javascript to parse the incoming JSON object.
This code appears to work in some cases - correctly parsing the incoming JSON - but fails in almost every circumstance. The error is cannot read property of length undefined.
Here's the test api that works: https://services.odata.org/V4/TripPinService/People
Here's the code:
var people = JSON.parse(json).value;
var arr = [];
function getCountry(member) {
try {
return member.fields.name;
} catch(err) {
return "";
}
}
for (i = 0; i < people.length; i++) {
var member = people[i];
var obj =
{
"name": member.name,
"Country": getCountry(member),
"alias": member.alias
};
arr.push(obj);
}
return arr;
Check your first line where is "json".I think you didn't defined a json file from which you are getting data.
Not sure exactly what you are doing to fetch the response, but I was able to get this working pretty easily:
fetch("https://services.odata.org/V4/TripPinService/People")
.then(response => response.json())
.then(data => {
var people = data.value;
var arr = [];
function getCountry(member) {
try {
return member.AddressInfo[0].City.CountryRegion;
} catch(err) {
return "Country Info Not Available";
}
}
for (i = 0; i < people.length; i++) {
var member = people[i];
var obj =
{
"name": member.FirstName,
"Country": getCountry(member),
"alias": member.alias
};
arr.push(obj);
}
console.log(arr);
});
Maybe this will give you some ideas.
I have checked the json from the given url. So, in your code the properties like 'member.name', 'member.alias', 'member.fields.name' doesn't exist.
Try using the exact property names from the json:
{
"#odata.context": "http://services.odata.org/V4/TripPinService/$metadata#People",
"#odata.nextLink": "https://services.odata.org/V4/TripPinService/People?%24skiptoken=8",
"value": [
{
"#odata.id": "http://services.odata.org/V4/TripPinService/People('russellwhyte')",
"#odata.etag": "W/\"08D817F8EC7DAC16\"",
"#odata.editLink": "http://services.odata.org/V4/TripPinService/People('russellwhyte')",
"UserName": "russellwhyte",
"FirstName": "Russell",
"LastName": "Whyte",
"Emails": [
"Russell#example.com",
"Russell#contoso.com"
],
"AddressInfo": [
{
"Address": "187 Suffolk Ln.",
"City": {
"CountryRegion": "United States",
"Name": "Boise",
"Region": "ID"
}
}
],
"Gender": "Male",
"Concurrency": 637285705159912400
}
]
}
What I am trying to say is that use the names exactly in json like 'member.UserName', 'member.AddressInfo[0].Name' etc.

Retrieving JSON response data with dynamic key [duplicate]

This question already has answers here:
Accessing a JavaScript's object property without knowing that property name
(3 answers)
How to access the first property of a Javascript object?
(23 answers)
Getting the first index of an object
(14 answers)
Closed 3 years ago.
I'm calling an API in my application and need to drill down the JSON response. Within it there is a random string that changes so I can't hardcode the value. Is there a way I can access dataset1 no matter what the random string is?
{
"data": {
"Random String that Changes": {
"dataset1": {
"date": {...}
},
"dataset2":{
"date": {...}
}
}
},
"something else": {
...
},
"something else": {
...
}
}
Previously I was hard coding the drill down like such:
this.props.data.randomData['Random String that Changes'].dataset1.date
Also tried:
this.props.data.randomData[0].dataset1.date
You can get all the keys of the object using
const keys = Object.keys(this.props.data);
Now keys is an array of all keys , but if you json always only has 1 key, you can get your data using
this.props.data.randomData[keys[0]].dataset1.date
You can get dataset1
const values = Object.values(this.props.data)
console.log(values[0]['dataset1'])
Make sure that your json includes the "Random String that changes" at first place as shown in your above format.
Reference: Object.values
Try accessing the object like this :
const obj = this.props.data;
obj[Object.keys(obj)[0]].dataset1.date
Reference: How to access the first property of an object in Javascript?
Consider sample data in myObj.
var myObj = {
"data" : {
"Random String that Changes": {
"dataset1": {
"date": "123"
},
"dataset2":{
"date": "123"
}
}
}
}
var randomString =myObj[Object.keys(myObj)[0]];
var dataset1Date =randomString[Object.keys(randomString)[0]].dataset1.date;
console.log(dataset1Date);
So in this way you can access the date which you are trying with
this.props.data.randomData['Random String that Changes'].dataset1.date
Please check the below code for the solution.
var response = {
"data": {
"Random String that Changes": {
"dataset1": {
"date": {...}
},
"dataset2":{
"date": {...}
}
}
},
"something else": {
...
},
"something else": {
...
}
};
var dataInRandomKey = response.data[Object.keys(response.data)[0]];
Now, you have the whole JSON object (in current example, response['data']['Random String that Changes']) in dataInRandomKey variable.
You can try for in loop
var a = {
"data": {
"Random String that Changes": {
"dataset1": {
"date": {...}
},
"dataset2":{
"date": {...}
}
}
},
"something else": {
...
},
"something else": {
...
}
}
var response = a.data;
for(var key in response) {
console.log(response[key].dataset1);
}

Array of key-value pair JSON object parsing

Hi I have have a given array of JSON object in a file:
file.json:
[
{
"id": "xccdf_saphana.content_profile_test1",
"info": {
"applicable_platforms": ["SUSE", "RHEL", "SUSE FOR SAP APP"],
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System"
}
},
{
"id": "xccdf_saphana.content_profile_test2",
"info": {
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System"
}
}
]
Below is the way I am reading it.
var obj = JSON.parse(fs.readFileSync(file.json, 'utf8')); // read the file
myID = "xccdf_saphana.content_profile_test2";
var myInfo = getInfobyID(myID);
function getInfobyID(myID) {
// Got messed up, tried changing JSON structure multiple time, so that I can easily parse it.
for(var i=0; i < obj.length; ++i) {
if(obj[i].id == myID)
return obj[i].info;
}
}
Is their any way I can optimize it, as I will be recursively searching for multiple myID later.
Turn your json into an object rather than an array. Then you can make quick lookups.
let hash = obj.reduce((agg, e) => {
agg[e.id] = e;
return agg;
}, {});
let value = hash["xccdf_saphana.content_profile_test2"].info;
The naming 'obj' is a bit confusing here since it is actually an array of objects (from the JSON file).
Try something like:
var myArrOfObj = JSON.parse(fs.readFileSync(file.json, 'utf8'));
var myID = "xccdf_saphana.content_profile_test2";
var myInfo = getInfobyID(myID);
function getInfobyID(myID){
var matchingObj = myArrOfObj.find((obj) => obj.id === myID);
// Fallback to empty string since there might be no match.
return (matchingObj) ? matchingObj.info : '';
}
You can use Array.reduce to convert your array into an object with key as id and value as info.
Now you can just return the object[id] and get the info without iterating everytime.
var json = [{
"id": "xccdf_saphana.content_profile_test1",
"info": {
"applicable_platforms": ["SUSE", "RHEL", "SUSE FOR SAP APP"],
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type": "System"
}
},
{
"id": "xccdf_saphana.content_profile_test2",
"info": {
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type": "System"
}
}
];
var data = json.reduce((acc, curr) => {
acc[curr.id] = curr.info;
return acc;
}, {});
function getInfobyID(data, id) {
return data[id];
}
console.log(getInfobyID(data, "xccdf_saphana.content_profile_test2"));
Based on this requirement:
Is their any way I can optimize it...
You may want to store the ID value as the key of a map, and any info related to it as the value. This way, whenever you are searching, if you already have the ID yo can access the data for that ID in constant time, or O(1), as opposed to linear time, or O(n).
This is the only way to speed up your search without more complex data structures, but it comes with one caveat which is that you no longer have a list. You will be using a map.
Change this:
[
{
"id": "xccdf_saphana.content_profile_test1",
"info": {
"applicable_platforms": ["SUSE","RHEL","SUSE FOR SAP APP"],
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System" }
},
{
"id": "xccdf_saphana.content_profile_test2",
"info": {
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System" }
}
]
To this:
{
"xccdf_saphana.content_profile_test1": {
"applicable_platforms": ["SUSE","RHEL","SUSE FOR SAP APP"],
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System"
},
"xccdf_saphana.content_profile_test2": {
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System"
}
}
Now you don't need any loops. You just have one object, with each member of the object representing a different item.
In your code, you can simply do obj[myId] and you will either get undefined if it doesn't exist, or you will get an object of the matching result.
This is the fastest a search could possibly be, but again it requires a map-like data structure and not a list.
If you absolutely must use a list, the only real optimization to be made is as follows:
Cache your list length, so you do not have to calculate it on each iteration of the loop
Your new getInfobyID could look like this:
function getInfobyID(myID){
var len = obj.length;
for (var i=0; i < len; ++i){
if( obj[i].id == myID)
return obj[i].info;
}
}

Using string in referencing JSON object in request

Using a fetch request to get some data. The JSON object path depends on a string variable. How would I convert the string into an object that can be referenced as an array in the path. Here's my code:
var path = 'bob';
fetch(request)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
}).then(function(json) {
var data = json.message.path[0].text;
}).catch(function(error) {
console.log(error);
});
JSON:
{
"message": {
"bob": [
{
"name_id": "3351",
"name": "bob",
"text": "lorem ipsum"
},
{
"name_id": "34562",
"name": "bob",
"text": "lorem ipsum2"
}
]
}
Basically, path defines the correct object to be used in the dot notation. BUT - the object also has to be able to reference the array.
Any solutions?
You could try using:
var data = json.message[path][0].text;
where path is the name of the object as you defined:
path = "bob";
If you have a path variable in the format user.index, you could reference the corresponding message in your JSON like this:
path = path.split(".");
var name = path[0], index = path[1];
var data = json.message[name][index].text;
If path is "bob.1", data would become "lorem ipsum2"
json.message[name] evaluates to the array of messages. To index into that array, just put brackets after the value, like any other array: json.message[name][index], which is equivalent to (json.message[name])[index], which is equivalent to var array = json.message[name] then array[index].
Note that this solution does no error checking, and will throw an error if the given user isn't in json.message.

Parsing JSON object

How I can parse 2 JSON objects? e.g
AJAX return just one Object appear's correctly.
Object {32 : "Joseph"}
But, when return more than 2 objects, I've got this:
ResponseText: "{"users":{"32":"Jospeh"}}{"users":{"48":"Jospeh K."}}"
I already trieD to parse with JSON.parse but returns an error: "Uncaught SyntaxError: Unexpected token {"
So, How I can parse to return something like this:?
Object {32 : "Joseph"}
Object {48 : "Joseph K"}
Instead of "responseText"
Considerations:
If returns just ONE object, appears correctly in console(example);
If returns more than TWO objects, appears responseText;
AJAX dataType: JSON
I'll be very grateful if someone can help with this. =D
PHP:
public function get_error_message()
{
$message = "";
foreach ($this->errors as $value) {
if ($value instanceof UsersError) {
$message.= json_encode(array('errors' => array($value->getCode() => $value->getMessage())));
}
}
return $message;
}
The problem is in your PHP code. You can't simply concatenate JSON and think that it will be valid.
Instead of
$message = "";
foreach ($this->errors as $value) {
if ($value instanceof UsersError) {
$message.= json_encode(array('errors' => array($value->getCode() => $value->getMessage())));
}
}
you should generate a proper PHP object, and then encode it to JSON once.
For example, in your case, it can be an array:
$errorsArray = array();
foreach ($this->errors as $value) {
if ($value instanceof UsersError) {
$errorsArray[] = array($value->getCode() => $value->getMessage());
}
}
echo json_encode(array('errors' => $errorsArray));
Then, a result will be the following no matter how many objects it returns - none,
{
"errors": []
}
only one or
{
"errors": [
{"32": "Joseph"}
]
}
many
{
"errors": [
{"32": "Joseph"},
{"48": "Joseph K."}
]
}
In JavaScript you will be able to do:
$.ajax({}).done(function(data) {
console.log(data.errors.length);
});
You can generate another JSON response which will be more convenient to work with in JavaScript. It's up to your requirements and fantasy.
For example, I would do a single associated array:
PHP:
$errorsArray = array();
foreach ($this->errors as $value) {
if ($value instanceof UsersError) {
$errorsArray[$value->getCode()] = $value->getMessage();
}
}
echo json_encode(array('errors' => $errorsArray));
JSON:
{
"errors": {
"32": "Joseph",
"48": "Joseph K."
}
}
That's not a valid JSON object. It is 2 JSON object in string representation concatenated together, which as far as I know is not valid. If you can't change the back-end, and you have to process this and can guarantee it is always 2 JSON object concatenated together, then you'll have to use string parsing to split them before sending them into JSON.parse(...) individually to get 2 JSON objects back.
this is not really standard way and your json is not valid:
but try this
str_data = "{'users':{'32':'Jospeh'}}{'users':{'48':'Jospeh K.'}}";
str_data = str_data .replace("}{", "}}{{");
items = str_data .split("}{");
object_items = [];
for(i =0; i < items.length; i++){ object_items[i] = JSON.parse(items[i]); }
Your JSON is invalid, try push users into an array.
var obj = {
"users": [
{
"name": "Jospeh",
"age": 32
},
{
"name": "Joseph K",
"age": 48
}
]
}
And for new users just push...
obj.users.push({ "name": "Neil A.", "age": 72 });

Categories