Related
I'm having an issue with a parser (in this case PowerBI) not taking values that are not quoted.
The example JSON file which comes from an API is validating ok, but PowerBI is not having any of it:
{'requester_id': 361114274894, 'submitter_id': 361114274894, 'assignee_id': 361282665913, 'organization_id': 360009532534, 'group_id': 360000498954, 'name':'John Doe'}
I'd like to find all values without quotes so I can replace them.
Please help.
It seems like you'd like to convert your int values to string.
var json = {'requester_id': 361114274894, 'submitter_id': 361114274894, 'assignee_id': 361282665913, 'organization_id': 360009532534, 'group_id': 360000498954, 'name':'John Doe'}
Object.keys(json).forEach(i => json[i]=json[i].toString());
// output
json
{
assignee_id:"361282665913"
group_id:"360000498954"
name:"John Doe"
organization_id:"360009532534"
requester_id:"361114274894"
submitter_id:"361114274894"
}
The issue is with the use of single quotes instead of double quotes around the property names.
let correctedInput = input.replace(/'/g, '"');
let parsedInput = JSON.parse(correctedInput);
parsedInput will now be your javascript object.
input.replace(/'/g, '"') will find and replace all ' characters, and replace them with " characters. This should work fine unless any of your property values have single quotes in them - For example, the name O'malley will be parsed incorrectly.
You can use the for in loop. Assuming all non string items are numbers the following will work.
const obj = {
a: 123,
b: "234234",
c: 09,
};
console.log(obj);
for (key in obj) {
obj[key] = obj[key] + "";
}
console.log(obj);
If the goal is to gather all the keys with non-string values rather than replacing them you can save them to an array and manipulate them later:
const obj = {
a: 123,
b: "234234",
c: 09,
};
const arr = [];
for (key in obj) {
if (typeof obj[key] !== "string") {
arr.push(key);
}
}
console.log(arr);
You can perform the regex pattern matching as below in Java
String rtype="^\"|\"$";
String value = ((JSONObject) nameOfObject).get("key").toString().matches(rtype);
or
((JSONObject) nameOfObject).get("key").toString().replaceAll(rtype);
I have data in unordinary format const variations
const variations = {
0: "{"productPriceLocal": "16990.00", "productId": "30028132"}",
1: "{"productPriceLocal": "22990.00", "productId": "30028233"}"
};
// this code doesn't work
// console.log(_.map(variations, 'productId'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
and I want this to convert to normal JS object like this, which with I can normally work
const object = {
0: {
productId: 30028132,
...
},
...
}
I tried to use lodash, doesn't work well. Does Anyone know, what I should do?
The first problem you have is that "{"productPriceLocal": "16990.00", "productId": "30028132"}" includes unescaped quotes that are terminating the string before you want it to (resulting in errors). So if you contain that string with single quotes your first problem should be fixed.
Then parsing the JSON objects as done below should produce the output you are looking for, no lodash nessecary.
const variations = {
0: '{"productPriceLocal": "16990.00", "productId": "30028132"}',
1: '{"productPriceLocal": "22990.00", "productId": "30028233"}'
};
var output = {};
for(key in variations) {
output[key] = JSON.parse(variations[key]);
}
console.log(output);
You could use Array reduce and Object.keys methods to map your object to a single object of the type you're wanting.
//Make sure you escape the quotes in your JSON strings.
const variations = {
0: "{\"productPriceLocal\": \"16990.00\", \"productId\": \"30028132\"}",
1: "{\"productPriceLocal\": \"22990.00\", \"productId\": \"30028233\"}"
};
let parsedValues = Object.keys(variations) // Get keys as an array [0,1]
.reduce((obj, key) => {
// parse to an object.
obj[key] = JSON.parse(variations[key]);
return obj;
}, {} /* initialization object */);
console.log(parsedValues);
That so crazy, but I'm trying to convert a JSON to a JSON for any reason.I have json and i checked json at http://jsonlint.com, it's ok.
{"d": "[{\"ID\":\"VN00000123\",\"NAME\":\"JOHN GREEN\",\"GENDER\":\"Male\",\"BIRTHDAY\":\"15-10-1987\"},{\"ID\":\"VN00000456\",\"NAME\":\"MERRY BLUE\",\"GENDER\":\"Female\",\"BIRTHDAY\":\"03-12-1983\"},{\"ID\":\"VN00000789\",\"NAME\":\"BLACK BROWN\",\"GENDER\":\"Male\",\"BIRTHDAY\":\"09-07-1990\"}]"}
Now, what I need convert it like this at the following
{
"columns": [
["ID"],
["NAME"],
["GENDER"],
["BIRTHDAY"]
],
"data": [
[
"VN00000123",
"JOHN GREEN",
"Male",
"15-10-1987"
],
[
"VN00000456",
"MERRY BLUE",
"Female",
"03-12-1983"
],
[
"VN00000789",
"BLACK BROWN",
"Male",
"09-07-1990"
]
]
}
Somebody've ideas for this, share with me (using javascript or jquery). Thank you so much.
This algorithm is pretty straightforward--something like the following should work:
function parse(a) {
//create object to return
var ret = {
columns: [],
data: []
};
//iterate the source array
a.forEach(function(item, i) {
if (i === 0) {
//first time through, build the columns
for (var key in item) {
ret.columns.push(key);
}
}
//now build your data item
ret.data[i] = [];
//use the column array to guarantee that the order of the fields in the source string doesn't matter
for (var j = 0; j < ret.columns.length; j++) {
var key = ret.columns[j];
ret.data[i].push(item[key]);
}
});
return ret;
}
var j = {
"d": "[{\"ID\":\"VN00000123\",\"NAME\":\"JOHN GREEN\",\"GENDER\":\"Male\",\"BIRTHDAY\":\"15-10-1987\"},{\"NAME\":\"MERRY BLUE\",\"BIRTHDAY\":\"03-12-1983\",\"ID\":\"VN00000456\",\"GENDER\":\"Female\"},{\"GENDER\":\"Male\",\"ID\":\"VN00000789\",\"NAME\":\"BLACK BROWN\",\"BIRTHDAY\":\"09-07-1990\"}]"
};
//j is an object with one property (d) that is a JSON string that needs parsing
var o = parse(JSON.parse(j.d));
console.log(o);
You can try this example using jQuery:
https://jsfiddle.net/de02fpha/
var dump = {"d": "[{\"ID\":\"VN00000123\",\"NAME\":\"JOHN GREEN\",\"GENDER\":\"Male\",\"BIRTHDAY\":\"15-10-1987\"},{\"ID\":\"VN00000456\",\"NAME\":\"MERRY BLUE\",\"GENDER\":\"Female\",\"BIRTHDAY\":\"03-12-1983\"},{\"ID\":\"VN00000789\",\"NAME\":\"BLACK BROWN\",\"GENDER\":\"Male\",\"BIRTHDAY\":\"09-07-1990\"}]"};
var parse = function(json) {
var columns = [];
var data = [];
$.each(json, function(index, row) {
var element = [];
for (var key in row) {
if (columns.indexOf(key) == -1) columns.push(key);
element.push(row[key]);
}
data.push(element);
});
return {columns: columns, data: data};
};
var json = $.parseJSON(dump.d);
console.log(parse(json));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
In javascript, the built in JSON class provides the two tools you need to format your JSON, no need for jquery:
JSON.parse() will handle parsing the text, and JSON.stringify can handle taking our parsed JSON and turning into a nice pretty string.
Let's slap them together.
Start with parsing and storing the JSON:
var parsedData = JSON.parse(dataToFormat);
Now to print our parsed data, we need to learn a little bit about the stringify function, specifically its space argument. Per MDN:
JSON.stringify(value[, replacer[, space]])
The space argument may be used to control spacing in the final string. If it is a number, successive levels in the stringification will each be indented by this many space characters (up to 10). If it is a string, successive levels will be indented by this string (or the first ten characters of it).
JSON.stringify({ uno: 1, dos: 2 }, null, '\t');
// returns the string:
// '{
// "uno": 1,
// "dos": 2
// }'
Note that the above code sample uses the tab character, but as described in the doc you can simply insert a number and it will use that number of spaces instead.
Alright let's print
var prettyData = JSON.stringify(parsedData, null, '\t');
prettyData should now contain a neatly formatted and indented string.
You can throw this into one line if you'd like:
var prettyData = JSON.stringify(JSON.parse(dataToFormat),null,'\t');
Now, if you wanted to add a key or something to the very top of the JSON object, you could simply define some kind of key object and attach it to the object you pass in to JSON.stringify. JSON.parse gives you a standard object, so modify it like you would any other.
I am looking for a way to write a JSON object to a file, but maintaining the same formatting with the orignal.
I have managed to write the content using writeFileSync(path,data) and JSON.stringify() but struggling to figure out how to customise the formatting. The options JSON.stringify accepts seem to format only the number of spaces.
Is there any way tho using JSON.stringify to generate the following formatting
{
"key1" :{"key": "value1","key": "value2"},
"key2" :{"key": "value1","key": "value2"}
}
instead of the one generated by default
{
"key1":
{
"key": "value1",
"key": "value2"
},
"key2":
{
"key": "value1",
"key": "value2"
},
}
Unfortunately not, you can use the space argument to define the spacing of the objects as they fall in on the tree. What you're proposing would require custom formatting using something like regular expressions to format the strings after you stringify it.
Below you'll find some sample code to do what you're looking to do however. You can append all of these into a single command like JSON.stringify(myJSON, null, ' ').replace(/: \{\n\s+/g, ': {').replace(/",\n\s+/g, ', ').replace(/"\n\s+\}/g, '}');, however so you could see what I did, I broke it down step by step.
const myJSON = {
"key1":{"key": "value1","key2": "value2"},
"key2":{"key": "value1","key2": "value2"}
}
let myString = JSON.stringify(myJSON, null, ' ').replace(/: {/g, `${' '.repeat(5)}: \{`); //Set the key spacing
myString = myString.replace(/: \{\n\s+/g, ': {'); //Bring the child bracket on the same line
myString = myString.replace(/",\n\s+/g, ', '); //Bring all the other objects for that array up
myString = myString.replace(/"\n\s+\}/g, '}'); //Pull the closing bracket on the same line
const myCompactString = JSON.stringify(myJSON, null, ' ').replace(/: {/g, `${' '.repeat(5)}: \{`).replace(/: \{\n\s+/g, ': {').replace(/",\n\s+/g, ', ').replace(/"\n\s+\}/g, '}'); //Done all at once
console.log(`myString: ${myString}`);
console.log(`myCompactString: ${myCompactString}`);
Building on KevynTD's great answer!
to keep Arrays of strings ['song', 'bird'] from changing to {'0': 'song', '1': 'bird'} index keyed objects. Add the if (Array.isArray(this)) obj = this; to the singleLineOBJ function.
const singleLineOBJ = function () {
let obj = { ...this }; // To not change any toJSON
if (Array.isArray(this))
obj = this; // override converting array into object
delete obj.toJSON // To not fall in a stringify loop
I want format like this:
var house = {
family: {
surname: "Smith",
people: 4,
pets: {
dogs: {number:1, names:["toby"]},
cats: {number:2, names:["bob", "boo"]},
platypus: {number:1, names:["perry"], codename: ["agent p"]},
}
},
livingRoom: [
{name:"couch", amount:2},
{name:"shelf", amount:1},
{name:"nightstand", amount:1},
{name:"television", amount:1},
],
bedroom: [
{name:"bed", amount:1},
{name:"wardrobe", amount:1},
{name:"shelf", amount:2},
],
}
It is a similar problem, but with more specific object keys, within a more complex tree of objects, and it started to get quite complicated to do this with just a regex. So, I created a function using toJSON and the stringify replacer as tools to handle this.
The function I created has some limitations, like just being able to define singleLine and multiLine only objects, and not numeric or text lists for example. It also has the limitation of some specific characters that are used for a replacement scheme, they are unusual characters, but look to confirm if you must replace them. The characters are four: '╲' (fake \), '”' (fake "), '→' and '←', if your object contains any of them you can replace them at the very beginning of the function.
Here an example with the function working:
// Custom Stringfy
const customStringify = function (
obj,
replacer,
space = "\t",
{
singlelineObjectKeys = [],
multilineObjectKeys = [],
singlelineChildKeys = [],
multilineChildKeys = [],
singlelineInsideList = [],
}
) {
// WARNING
// - This function will make a mess if your Object contain some of the following characters:
const fakeNewLine = `╗`; // (replace \n in middle of process)
const fakeTab = `╦`; // (replace \t in middle of process)
const fakeQuote = `║`; // (replace " in middle of process)
const startString = `╠`; // (add to start in middle of process)
const endString = `╣`; // (add to end in middle of process)
// So a solution in this case can be replace this chars by others not used (dont use characters that can mess the regex)
// First make a stringify to solve any toJSON in the main object, then copy the main object stringfied to create all the necessary new toJSON
let objModified = JSON.parse(JSON.stringify(obj, replacer));
// Convert an entire object to single line string
const singleLineOBJ = function () {
// To not change any toJSON
const obj = Array.isArray(this) ? [...this] : { ...this };
// To not fall in a stringify loop
delete obj.toJSON;
// Mark the startString and endString
return (
startString +
JSON.stringify(obj)
// Replace all " by fakeQuote
.replace(/"/g, fakeQuote) +
endString
);
};
// Convert an entire object to multi line string
const multiLineOBJ = function () {
// To not change any toJSON
const obj = Array.isArray(this) ? [...this] : { ...this };
// To not fall in a stringify loop
delete obj.toJSON;
// Mark the startString and endString
return (
startString +
JSON.stringify(obj, null, "\t")
// Replace all " by fakeQuote
.replace(/"/g, fakeQuote)
// Replace \n using fakeNewLine
.replace(/\n/g, fakeNewLine)
// Replace \t using fakeTab
.replace(/\t/g, fakeTab) +
endString
);
};
// Checks all keys on the object
const throughEveryKey = function (key, value) {
let obj = this;
// objects inside specific keys to become single-line
if (singlelineObjectKeys.includes(key)) {
obj[key].toJSON = singleLineOBJ;
}
// objects inside specific keys to become multi-line
if (multilineObjectKeys.includes(key)) {
obj[key].toJSON = multiLineOBJ;
}
// objects containing the following keys to become single-line
if (singlelineChildKeys.includes(key)) {
obj.toJSON = singleLineOBJ;
}
// objects containing the following keys to become multi-line
if (multilineChildKeys.includes(key)) {
obj.toJSON = multiLineOBJ;
}
// names of list of objects to each list-item become single-line
if (singlelineInsideList.includes(key)) {
obj[key].forEach(
(objectInsideList) => (objectInsideList.toJSON = singleLineOBJ)
);
}
return value;
};
// Just use stringify to go through all object keys, and apply the function to implement "toJSON" in right places, the result of stringify is not used in this case (WIP)
JSON.stringify(objModified, throughEveryKey);
// Use stringfy with right replacers, end result
return (
JSON.stringify(objModified, null, "\t")
// Put in all start of line the right number of Tabs
.replace(new RegExp("(?:(?<=(?<leadTab>^\t*).+?)(?<newLine>" + fakeNewLine + ")(?=.+?))+", "gm"), "$&$1")
// Replace the fake tab by the real one
.replace(new RegExp(fakeTab, "gm"), "\t")
// Replace the fake new line by the real one
.replace(new RegExp(fakeNewLine, "gm"), "\n")
// Replace the fake quote by the real one
.replace(new RegExp(fakeQuote, "gm"), '"')
// Remove start and end of line from the stringfied object
.replace(new RegExp('"' + startString, "gm"), "")
.replace(new RegExp(endString + '"', "gm"), "")
// Replace tab by custom space
.replace(/(?<=^\t*)\t/gm, space)
);
};
var house = {
family: {
surname: "Smith",
people: 4,
pets: {
dogs: {
number: 1,
names: ["toby"],
},
cats: {
number: 2,
names: ["bob", "boo"],
},
platypus: {
number: 1,
names: ["perry"],
codename: ["agent p"],
},
},
},
livingRoom: [
{
name: "couch",
amount: 2,
},
{
name: "shelf",
amount: 1,
},
{
name: "nightstand",
amount: 1,
},
{
name: "television",
amount: 1,
},
],
bedroom: [
{
name: "bed",
amount: 1,
},
{
name: "wardrobe",
amount: 1,
},
{
name: "shelf",
amount: 2,
},
],
};
console.log("A custom stringify:\n\n");
console.log(
customStringify(house, null, " ", {
singlelineObjectKeys: ["dogs", "cats", "platypus"],
multilineObjectKeys: ["family"],
multilineChildKeys: [],
singlelineChildKeys: [],
singlelineInsideList: ["livingRoom", "bedroom"],
})
);
console.log("\n\n\n");
console.log("A normal stringify:\n\n");
console.log(JSON.stringify(house, null, " "));
You need to pass some information to work, you don't need to use everything, but I'll explain the cases that I left prepared to format between multiLine and singleLine:
singlelineObjectKeys: Put here the keys for objects / arrays that need to be on a single line
multilineObjectKeys: Place here the keys of objects / arrays that need to be formatted in several lines
multilineChildKeys: If you do not want to specify a parent object, as they can have many, specify a child key for the parent object to be formatted on multiple lines
singlelineChildKeys: If you don't want to specify a parent object, as they can have many, specify a child key for the parent object to be formatted on a single line
singlelineInsideList: If you have a list of objects, and you want all objects within that list to be formatted in a single list, put the key for that list here
In the example above the code used was this:
customStringify(house, null, '\t', {
singlelineObjectKeys: ["dogs","cats","platypus"],
multilineObjectKeys: ["family"],
singlelineInsideList: ["livingRoom","bedroom"],
})
But this will result the same for example:
customStringify(house, null, '\t', {
singlelineChildKeys: ["name","names"],
})
As I had researched this in several places and found nothing about it, I register my solution here (which was one of the places I looked for). Feel free to use!
Edit:
Updated to receive lists as single line or multiline on objects, thanks to #mj1701's suggestion.
Updated way to replace newline and tab, made code 20% faster
Old unresolved problem: After defining singlelineInsideList, if you put a multilineObjectKeys that is inside, the code tab has a problem, in progress
I am modifying the code in free time, it is not 100% finished, but it already works in several tested cases.
If you found any bugs, please comment here!
I query two arrays from the database and turn them into json format. The set up is like this:
{"groups":"[apple,bee,car,dogs,egos,fruits]", "members":"[g,h,i,j,k,l]"}
I am trying to access each element in groups. The groups array is a list. I tried using index, and it's returning me groups[0] = 'a', groups[1] = 'p'... So using index doesn't work.
I also want to count how many elements in the groups array or in the members array, and using .length only give me back the character length, not the actual numbers of elements.
Any advice would be appreciated. Thanks.
JSON.parse(groups) will not work, because [apple,bee,car,dogs,egos,fruits] is not correct JSON string.
["apple","bee","car","dogs","egos","fruits"] - is correct JSON string, that can be parsed.
P.S. members is not correct JSON string too.
// If you have some data
data = {
groups: ["apple", "bee", "car", "dogs", "egos", "fruits"],
members: ["g", "h", "i", "j", "k", "l"]
};
// you can convert it to JSON string
jsonData = JSON.stringify(data);
console.log('JSON data: ', jsonData);
// and then parse this string
restoredData = JSON.parse(jsonData);
// after this you can access object members again
console.log('groups[0]: ', restoredData.groups[0]);
This is happening because "[apple,bee,car,dogs,egos,fruits]" it's an string. You have to parse it before accessing the element.
Let's say that you have the JSON in the variable test, then we have to delete [ and ] and split the string like this:
test.groups = test.groups.replace("[", "")
test.groups = test.groups.replace("]", "")
test.groups = test.groups.split(',')
And then now it contains:
["apple", "bee", "car", "dogs", "egos", "fruits"]
You should consider constructing the array differently from the database.
You are getting those letters because they are in the position in the string that you are referencing with the index.
Consider using regex and the split() function to parse them as they are now:
var obj = {"groups":"[apple,bee,car,dogs,egos,fruits]", "members":"[g,h,i,j,k,l]"};
// Regex replaces the square brackets with blank spaces and splits by the
// comma into an array
var groups = obj.replace(/[\[\]']+/g,'').split(',');
var members = obj.replace(/[\[\]']+/g,'').split(',');
Now groups[1] will return 'bee'.
Read more about split() here.
It doesn't work because all elements of the array are in one string.
As has been mentioned this not correct JSON formatting, but sometimes you don't have control over how you get information. So although this is not a recommended answer, you could use simple string parsing to get back the values you want by doing, something like:
var stuff = JSON.parse('{"groups":"[apple,bee,car,dogs,egos,fruits]", "members":"[g,h,i,j,k,l]"}');
var groups = stuff.groups.split("[")[1].split("]")[0].split(",");
var members = stuff.members.split("[")[1].split("]")[0].split(",");
console.log(groups); // ["apple", "bee", "car", "dogs", "egos", "fruits"]
console.log(groups[1]); //bee
console.log(members[0]); //g
I would like to reiterate this is not an ideal solution, but sometimes it is all you can do.