I'm currently trying to parse the following JSON output.
These JSON objects are stored in one big string and not in a JSON array. As such it is not valid JSON.
{"output": "te\ns\nt"}
{"output": "test"}
This string also contains multiple new lines. So splitting on new lines is not an option.
Nevertheless is there any way of parsing this invalid JSON that it results in a valid array of JSON objects?
If your object-list (let's call it that) contains valid objects you can first make an array from each line and then go through that array and parse the JSON:
let data = `{"output": "test"}
{"output": "test"}`; //template string to make the newlines work flawless...
// first split on newline filter out "" map to the parsed JSON
data = data.replace(/}\n*/g, "}**").split("**") .filter(Boolean) .map(JSON.parse);
console.log(data);
Here's something dirty that might work.
let string = `{"output": "te\ns\nt"}
{"output": "test"}`
let json = JSON.parse(`[${string.replace(/}[\s]*\{/g, '}, {').replace(/\n/g, '\\n')}]`)
console.log(json) // [ { output: 'te\ns\nt' }, { output: 'test' } ]
Not pretty and quite fragile, but quick.
Related
I have a JSON string something similar to:
string str=[
{"name": "Dukes",
"lastname":"Chavez",
"salary":"10000",
"clearingbankAccinfo":"Westpac"}]
The issue is we have to clear the bank info, and that can be any value.
What we know for sure is it would come at the end of the string.
I need a regex pattern to remove this clearingbankAccInfo so that it looks something similar to:
string str=[
{"name": "Dukes",
"lastname":"Chavez",
"salary":"10000"}]
Unfortunately I would have not accepted this as input itself but this information comes from a diff process and I have no control over what they pass.
I have tried:
String str=str.replace(',"clearingbankAccInfo":\g[a-zA-Z0-9_:]\g+', '' )
But it doesn't work correctly
If you're working with something like JSON regex is the wrong solution. Simply parse the stringified data, and loop over it with something like map to extract and return the correct data. Then you can just make a string again out of that data.
const str = '[{"name": "Dukes","lastname": "Chavez","salary": "10000","clearingbankAccinfo": "Westpac"},{"name": "Bob","lastname": "Smith","salary": "20000","clearingbankAccinfo":"Lloyds"}]';
// Here we're creating a new variable called `newData` to hold
// the transformed data. We parse the data string and iterate over it
// (because it's now an array) with `map` which is an array method.
// With each iteration we take the object, grab the clearingBankAccinfo
// and just return everything else.
const newData = JSON.parse(str).map(obj => {
const { clearingbankAccinfo, ...rest } = obj;
return rest;
});
console.log(newData);
console.log(JSON.stringify(newData));
Additional documentation
Rest parameters
Working with JSON
Destructuring assignment
str=str.replace(/,?"clearingbankAccinfo":"\w+"/g, '');
I am using angular5.I have a questionOrderList which is a string which contains multidimensional array in string format. What I need to do is to parse the array in string format back to multidimensional array type. Currently I have used the JSON.parse method my code looks like.
console.log("qorder service : "+questionOrderList)
console.log("qorder service parsed:" +JSON.parse(questionOrderList))
The output I am getting is
qorder service : [[3290],[3287],[3289,3293],[3295]]
qorder service parsed: 3290,3287,3289,3293,3295
But in case of array with one row it is correct
qorder service : [[3290,3287,3289,3293,3295]]
qorder service parsed: 3290,3287,3289,3293,3295
What you are going is correct, see this:
var questionOrderList = "[[3290],[3287],[3289,3293],[3295]]";
var parsedList = JSON.parse(questionOrderList);
console.log(parsedList)
The actual issue is how JS interprets string concatination with arrays. It implicitly calls .join(',') on the array as demonstrated here:
var questionOrderList = "[[3290],[3287],[3289,3293],[3295]]";
var parsedList = JSON.parse(questionOrderList);
console.log(parsedList);
console.log("" + parsedList);
console.log(parsedList.join(','))
is there anyway i can get this malformed json format which is odd i have no control over this json manually so i need to get this data and manipulate it with rxjs observable from http get
{
"firstNm": "Ronald",
"lastNm": "Mandez",
"avatarImage": "https://randomuser.me/api/portraits/men/74.jpg"
}
{
"firstNm": "Ronald",
"lastNm": "Mandez",
"avatarImage": "https://randomuser.me/api/portraits/men/74.jpg"
{
"firstNm": "Ronald",
"lastNm": "Mandez",
"avatarImage": "https://randomuser.me/api/portraits/men/74.jpg"
}
I tried with your JSON in the console and this seems to work. In the map function I've used you can probably implement more generic replacement methods to alter the strings, but it works for this example.
function fixBadJSON(response){
let badJSON = JSON.stringify(response); // added this edit in case you don't know how to get the response to a string
let arr = badJSON.split('}\n'); // Looks like the JSON elements are split by linefeeds preceded by closing bracket, make into arr length of 3
let fixedArr = arr.map((item)=>{ // map the array to another, replace the comma at the end of the avatarImage key. elements in array should be proper JSON
if(item[item.length] != '}') item += '}'; //put the brackets back at thend of the string if they got taken out in the split, probably a better way to handle this logic with regex etc
return item.replace('jpg",','jpg"')
});
let parsedJSON = JSON.parse(JSON.stringify(fixedArr));
return parsedJSON
}
Take the JSON data you've posted up there and copy it to a variable as a string and test the function, it will return a properly formatted array of JSON data.
Call that when you get a response from your service to transform the data. As far as the observable chains and any async issues you might be seeing those are separate things. This function is just designed to convert your malformed JSON.
My JSON is like below
{"_id":707860,"name":"Hurzuf","country":"UA","coord":{"lon":34.283333,"lat":44.549999}}
{"_id":519188,"name":"Novinki","country":"RU","coord":{"lon":37.666668,"lat":55.683334}}
{"_id":1283378,"name":"Gorkhā","country":"NP","coord":{"lon":84.633331,"lat":28}}
{"_id":1270260,"name":"State of Haryāna","country":"IN","coord":{"lon":76,"lat":29}}
{"_id":708546,"name":"Holubynka","country":"UA","coord":{"lon":33.900002,"lat":44.599998}}
It is a JSON without comma separation, how to read this file? I tried to parse the JSON and add commas in between, but couldn't do that either.
myapp.controller('Ctrl', ['$scope', '$http', function($scope, $http) {
$http.get('todos.json').success(function(data) {
var nuarr = data.toString().split("\n");
for(i in nuarr) {
myjson.push(i+",");
}
});
}]);
This format is typically called "newline-delimited JSON" or "ndjson"; there are several modules that can parse this, but if you're data set is small and you can do it all at once, you're on the right track:
var ndjson = "..." // assuming your data is already loaded in as a string
var records = ndjson.split('\n').map(function (record) {
return JSON.parse(record)
})
That simplifies it a bit, but then you have all of your records in an array, as parsed JSON objects. What you do to them after that is up to you, but the key takeaway here is that your JSON is a list of objects, not a single object: you don't want to parse it as a whole, but as individual records.
Say then, you want to create an object whose keys are the individual IDs; that might be helpful:
var recordHash = {}
records.forEach(function (record) {
recordHash[record._id] = record
})
Now you can address the individual records as recordHash['12345678'] assuming that 12345678 is the id of the record you wanted. You'll want to mutate the records into whatever data structure makes sense for your application, so it really depends on what you're looking for, but that example might get you started.
I really don't recommend trying to mutate the data that you're receiving into some other format before parsing; it's fragile. You'll find it much safer and more re-usable to parse out the data in the way you were provided it, and then transform it into whatever data structure makes sense for your application.
$http.get expects that response must be json. You can write your own custom response transformer to do that so.
$http({
url: 'todos.json',
method: 'GET',
transformResponse: function (data) {
return data.split('\n').map(function(line) {
return JSON.parse(line);
});
}
}).success(function (response) {
console.log(response);
// do whatever you want to do
// response will be of type array of objects
});
Your JSON needs to be a single object or array. Just joining a bunch of objects together with a comma does not define a single JSON object. Try this instead to get a parsable array of objects:
var nuarr = data.toString().split("\n");
myjson = '[' + nuarr.join(',') + ']';
Then JSON.parse(myjson) should return an array of objects. Alternatively, you can just map each element of nuarr to it's JSON-parsed value and collect the results in another array.
$http.get expects that response must be json. You can write your own custom response transformer to do that so.
$http({
url: 'todos.json',
method: 'GET',
transformResponse: function (data) {
return data.split('\n').map(function(line) {
return JSON.parse(line);
});
}
}).success(function (response) {
console.log(response);
// do whatever you want to do
// response will be of type array of objects
});
var myJson = nuarr.join(',');
But what are you really trying to do? Your code is pushing the strings with a comma added into an array, so end up with
["{...},", "{...},", ...]
As I see it, You have a collection of json objects, with the delimiter as newline.
Try this:
myapp.controller('Ctrl', ['$scope', '$http', function($scope, $http) {
$http.get('todos.json').success(function(data) {
myjson = data.split("\n").map(function(line) { return JSON.parse(line); });
});
}]);
Use a regexp to split into lines, then map each line into its JSON-parsed equivalent, yielding an array of the objects on each line:
input . match(/^.*$/gm) . map(JSON.parse)
Or use split as other answers suggest:
input . split('\n') . map(JSON.parse)
As stupid as it may seem, we got tired of using commas and quotes with JSON, along with not having comments or multiline strings.
Knowing that Douglas Crockford and his disciples would cry 'Blasphemy', we proceeded to write a specification, parser, and formatter for our own Relaxed Json syntax.
The fact is you don't really need commas, and quotes are only needed in a few exceptional cases. And you don't need newlines either.
With Relaxed Json, to make your example work, you would just put '[' and ']' around what you already have and call
val realJson = parser.stringToJson(...)
But you don't need newlines between the array values.
And you can also remove all the commas in-between your key-values.
And you don't need quotes around your keys.
So you could do this:
[
{ _id:707860 name:Hurzuf country:UA
coord:{lon:34.283333 lat:44.549999}
}
{ _id:519188 name:Novinki country:RU
coord:{lon:37.666668 lat:55.683334}
}
]
Link To Specification:
http://www.relaxedjson.org
Link To NPM
https://www.npmjs.com/package/really-relaxed-json
Paste the example here to see how easy it is to parse:
http://www.relaxedjson.org/docs/converter.html
Update 2022
#milkandtang answer put me on the right path but JSON.parse() gave me trouble and returned errors even after splitting the lines. It keeps complaining about lines being empty or malformated.
This is what works for me with New-Line Delimited JSON
var ndjson = data;//must be a string
//declare variable that will be array of json
var json = [];
//split
ndjson.split('\n').map(function (record) {
//regex to format each array to a json object
var array = JSON.parse(`[${record.replace(/\}\n\{/g, '},{')}]`);
//push to json array
json.push(array);
})
//pheeew...
console.log(json);
My code returns a JSON array, I think. The returned JSON array is stored in a javascript variable: result. If I
console.log(result);
in FF, I get the output
[{"id":"G24","value":"Zas, S"},{"id":"G75","value":"Wara, TS"},{"id":"G48","value":"Jala, S"}]
Validated on jsonLint to be correct json.
In my code, if I count the number of elements in the array like so:
var key, count = 0;
for(key in result)
{
count++;
}
console.log("result count is:" + count);
The output is 94 which is the length/count of characters in the array - [the sample output shown above is modified]
However, in the JSON tab in FF, it shows the result as being an array of objects:
0 Object { id="G24", value="Zas, S"}
1 Object { id="G75", value="Wara, TS"}
2 Object { id="G48", value="Jala, S"}
I have used alternative code pieces from 'stackoverflow' sources
for ( property in result )
{
if(result.hasOwnProperty(property))
{
count++;
}
}
And this has had the same outcome. How can I have iterate rightly over this array or array of objects or string or whatever else it is? And get the count please?. Thanks.
It sounds like you have an HTTP response returning a JSON document.
In the JSON tab, this is shown as JSON.
If your code, you are just taking the text of the response and operating on that.
You need to parse the JSON to create JavaScript objects.
Pass the string through JSON.parse and use json2.js to polyfill for older browsers.
You have to parse the JSON to create a JavaScript Array.
result = JSON.parse(result); // Now it's an array
console.log(result.length) // prints now what you want