i've following problem and since i upgraded my prototypeJS framework.
the JSON parse is not able anymore to convert this string to an object.
"{empty: false, ip: true}"
previously in version 1.6 it was possible and now it needs to be a "validated" JSON string like
'{"empty": false, "ip": true}'
But how can i convert the 1st example back to an object?
JSON needs all keys to be quoted, so this:
"{empty: false, ip: true}"
is not a valid JSON. You need to preprocess it in order to be able to parse this JSON.
function preprocessJSON(str) {
return str.replace(/("(\\.|[^"])*"|'(\\.|[^'])*')|(\w+)\s*:/g,
function(all, string, strDouble, strSingle, jsonLabel) {
if (jsonLabel) {
return '"' + jsonLabel + '": ';
}
return all;
});
}
(Try on JSFiddle) It uses a simple regular expression to replace a word, followed by colon, with that word quoted inside double quotes. The regular expression will not quote the label inside other strings.
Then you can safely
data = JSON.parse(preprocessJSON(json));
It makes sense that the json parser didn't accept the first input as it is invalid json. What you are using in the first example is javascript object notation. It's possible to convert this to an object using the eval() function.
var str = "({empty: false, ip: true})";
var obj = eval(str);
You should of course only do this if you have the guarantees the code you'll be executing is save.
You can find more information about the json spec here. A json validator can be found here.
edit: Thai's answer above is probably a better solution
const dataWithQuotes = str.replace(/("(\\.|[^"])*"|'(\\.|[^'])*')|(\w+)\s*:/g, (all, string, strDouble, strSingle, jsonLabel) => {
if (jsonLabel) {
return `"${jsonLabel}": `;
}
return all;
});
return dataWithQuotes
similar solution as above , but updated with arrow functions.
Related
My problem is that I have to concatenate all the text after the "product_link_href": in a huge serie of things (there are 200+ of these so I couldn't post the entire thing) like:
Solved snippet removed for privacy reasons
It's coming from an api, it's white in windows power shell, the name of the thing is response.data I'm using axios; I think this thing to the machine is just plain text, because it was green before I selected it whit .data ; but I still need all the text after "product_link_href": concatenated, in text format and sepsarated by ","
The code I am using is
axios.get('https://randomapi/' + id + '/json?api_token=examplenotrealapitoken').then(response => {
console.log(response.data);
});
I tried JSON.parse and stringify but nothing works.
The response from the server is stringified JSON objects that have been concatenated with line return characters "\n".
It is not JSON parseable because it is not an array, which it needs to be, to be valid JSON.
The approach I took is to coerce it to "an array of stringified JSON objects". Since each object is shallow, there is no nesting, so the } character is unambiguously the end of a stringified object.
You can call massiveJSONishString.split('}'), and you get an array of JSON-stringified objects with the trailing } missing on each one.
Then you map over that array, and for each element, add the trailing } that we threw away to array-ify it, and JSON.parse() that string, producing an array of JSON objects.
This is the code you are looking for:
const textArray = res.data.split("}");
const jsonArray = textArray.map(element => {
try {
return JSON.parse(`${element}}`);
} catch (e) {
return {
product_link_href: "MALFORMED JSON"
};
}
});
// console.log(jsonArray);
const product_link_hrefs = jsonArray.map(obj => obj.product_link_href);
const list = product_link_hrefs.join(", ");
console.log(list);
console.log(`You're welcome!`);
I discovered Javascript ES6 Template Literals today. Just one word: Awesome!
Question: How to store and load Template Literals as JSON? I load some files via XHR, followed by some JSON.parse() which doesn't support ` instead of ", so it seems one can't save Template Literals directly in the files.
Goal: To use this for dynamic strings and translation and to get rid of confusing stuff like ("Hello " + username + "! How are you?") which requires multiple strings to be stored for just one message, and instead save my stuff beautifully and simple as
`Hello, ${username}! How are you?`
where username points to the dynamic variable with the same name. Is that possible? If yes, how to achieve this? It's okay if i have to use a function to somehow convert the strings into Template Literals as long as it doesn't hit hard on the overall performance, but I would like to at least avoid eval.
You can create your own function to parse template literal,
function stringTemplateParser(expression, valueObj) {
const templateMatcher = /{{\s?([^{}\s]*)\s?}}/g;
let text = expression.replace(templateMatcher, (substring, value, index) => {
value = valueObj[value];
return value;
});
return text
}
console.log(stringTemplateParser('my name is {{name}} and age is {{age}}', {name: 'Tom', age:100}));
// output 'my name is Tom and age is 100'
You could always use JSON.stringify to enclose dynamic data:
const data = 'some value';
JSON.stringify({
data,
});
// expected: "{\"data\": \"some value\"}"
I found it easier to separate the problem in a few substrings of JSON. Create the key "message" and this key stores parts of the message. It also works well for i18n.
{
"message" : {
"_0": "first part ",
"_1": "after first variable. ",
"_2": "after another variable"
}
}
And then, after decoding it, you can access it like
${message._0}${variable}${message._1}${var2}${message._2}
Try json-templates. Looks like exactly what you're looking for.
Is there a way to parse NON wellformed JSON, other than using eval?
The background is, that I'm using data tag values to draw a graph like this:
<div id="data" data-idata="[1,2,3]" data-sdata="['foo','bar','baz']"></div>
This works flawlessly with numeric values, these values are delivered as an array directly in jQuery data, no need to parse JSON here.
However, for the labels a string array is to be passed. eval can parse the string in sdata just fine, but JSON.parse and jQuery.parseJSON fail, because it's not wellformed JSON.
var $data = $("#data").data(),
values;
// use eval
out("#out", eval($data.sdata)); // works...
// use JSON.parse
try
{
values = JSON.parse($data.sdata);
} catch(e) {
// silent catch
}
out("#out1", values); // values is undefined
I put together a JsFiddle here to check the thing.
You get error because ['foo','bar','baz'] contains single-quotation marks. JSON RFC specifies that string should be enclosed in double-quotation marks.
There could be a few work-arounds.
Switch quotation marks in the data- attributes:
<tag data-sdata='["foo","bar","baz"]' />
Or replace in Javascript:
values = JSON.parse($data.sdata.replace("'","\""));
You don't need to parse. Simply use .data(), the function does it for you.
I have changed your HTML, I have swapped quotes in line data-sdata="['foo', 'bar', 'baz']" as JSON should use in double-quotation(") marks.
HTML
<div id="data" data-idata="[1,2,3]" data-sdata='["foo", "bar", "baz"]'></div>
Script
out("#out1", $("#data").data('idata'));
out("#out2", $("#data").data('sdata'));
DEMO
Ofcourse you cannot easy parse corrupted data for 100% this goes for any data-formats and not only JSON.
If the reason the data are malformed are always the same you should fix it with some str_find and replacement functions.
If it is irregular you have no real chance except writing a really intelligenz and big algorithm. The best way here would be to try to extract the real raw data out of the corrupted string and build a real JSON string with valid syntax.
Try
html
<div id="data" data-idata="[1,2,3]" data-sdata='["foo","bar","baz"]'></div>
<div id="out1">out1</div>
<div id="out2">out2</div>
js
$(function () {
var out = function (outputId, elem, dataId) {
return $.each(JSON.parse($(elem).get(0).dataset["" + dataId])
, function (index, value) {
$("<ul>").html("<li>" + index + " -> " + value + "</li>")
.appendTo(outputId);
});
};
out("#out1", "#data", "idata");
out("#out2", "#data", "sdata");
});
jsfiddle http://jsfiddle.net/guest271314/4mJBp/
This question already has answers here:
Parse JSON in JavaScript? [duplicate]
(16 answers)
Closed 8 years ago.
I am trying to parse json source with javascript.
I have this json source:
var exam = '{
status : 'connected',
authResponse: {
accessToken: 'it is accessToken',
expiresIn:'2014-06-19',
signedRequest:'it is signedRequest',
userID:'mp172'
}
}';
To parse, I use JSON.parse(exam);
After this source, it is not working. I want to parse this source with javascript.
Actually, your json source is not valid.
According to JSON.org, member should be quote by "
Change exam to {"status":"connected","authResponse":{"accessToken":"it is accessToken","expiresIn":"2014-06-19","signedRequest":"it is signedRequest","userID":"mp172"}}
Take a look at JSON.stringify and JSON.parse.
var exam = {status : 'connected', authResponse: { accessToken: 'it is accessToken', expiresIn:'2014-06-19', signedRequest:'it is signedRequest', userID:'mp172' }};
// stringify the response first
stringify = JSON.stringify(exam);
// stringified result
console.log(stringify);
// parse the json
final = JSON.parse(stringify);
// parsed final result
console.log(final);
Here is the jsfiddle example
Your JSON is invalid , it should look something like this ,
{
"status": "connected",
"authResponse": {
"accessToken": "itisaccessToken",
"expiresIn": "2014-06-19",
"signedRequest": "itissignedRequest",
"userID": "mp172"
}
}
JSONLint show following error ,
"Proper" json data has both the property name and string values in double quotes. Browser parsers are very lenient though and the reason I think yours is failing is because it isn't a valid string. When you open the string with ', the string ends on the next ' it finds, so it should be choking when it tries to make sense of connected', after finding the string '{ status : '. If you wrapped your JSON in single double quotes (since it uses single quotes for values) that would probably work, but comphilip is right.
If you intended it to be a string to start with, make sure it is in one line. Otherwise, use (+) to append the string and then use JSON.parse to parse it to an object.
var exam = '{"status" : "connected","authResponse": {"accessToken": "it is accessToken","expiresIn":"2014-06-19","signedRequest":"it is signedRequest","userID":"mp172"}}'
var obj = JSON.parse(exam);
I have some data in the form
[
{
"name": "alex",
"fullname": "Alessandro Magno"
},
{
"name": "alex",
"fullname": "Alessandro Magno"
}
]
but (name and fullname) are not fixed, they may be "key"/"value", or whatever.
I'm also given a template to follow, e.g.:
var template = "<span>data.fullname (data.name)</span>".
My problem is the following:
I have to look for all the "data." in the string,
obtain the value following it (in this case, fullname and name),
and replace data. with my external source. E.g.
str.replace("data.<value>", source[value]);
In Javascript.
Thanks!
EDIT: I probably explained it wrongly. My source is defined (in this case, a name/fullname list in JSON format). I also have a template to follow. I have to replace the syntax used in the template (which is "data." ['data.' is fixed]) with the correspondent value of the source. Hope this is clearer now!
Re-thanks!
A simple replace call using a string will only replace a single instance of a substring. You'll have to use a regular expression.
Looking at what you're trying to do, I'd say you're probably looking for something like:
var s = "<span>data.fullname (data.name)</span>";
var replacements = {name: 'alex', fullname: 'alessandro'};//example
s.replace(/(data\.)([a-z]+)/g, function(a,b,c)
{
return b + (repl[c] || 'none');
});
This results in "data.alessandro (data.alex)"
How it works? Central to this approach is the regular expression:
/(data\.)([a-z]+)/g, which is quite basic:
(data\.): match and capture the literal string "data."
([a-z]+): again: match & capture 1 or more chars fater data. -> "data."
g: is the global flag, apply this patter to the entire string.
Now, for each match for this pattern that is found, instead of providing a replacement string, I provide a function, that is passed the matched substring (and the captured groups as separate arguments), and use the function construct a replacement string:
function(a, b, c)
{//a -> entire substring, b-> data., c-> string after data.
return b + (replacements[c] || 'none');// logical || to provide default string replacement
}
It's as simple as that, really. Given that your values are contained by objects, that are in an array, you could opt to code the following:
var vals = [{name: 'alex', fullname: 'alessandro'},{name: 'alex2', fullname: 'alessandro2'}],
results =[],
template = "<span>data.fullname (data.name)</span>";
for (var i=0;i<vals.length;++i)
results[i] = template.replace(/(data\.)([a-z]+)/g, function(a,b,c)
{
return b + (vals[i][c] || 'default');
});
Edit:
To remove data. substring, too, change the callback function (and pattern) to:
s.replace(/data\.([a-z]+)/function(a,c)
{
return replacements[c] || 'none';
});
In case of the code above:
for (var i=0;i<vals.length;++i)
results[i] = template.replace(/data\.([a-z]+)/g, function(a,c)
{
return vals[i][c] || 'default';
});
Is what you're after
If you need to use a template you could use template engine. Basically it will allow you to bind an object to a template. Behind the scene the template is parsed using regex. Pseudo-code:
var template = "<span>{fullname} ({name})</span>";
var html = template({ fullname: data.fullname, name: data.name });
To name a few:
http://handlebarsjs.com/
http://mustache.github.io/
http://underscorejs.org/
Underscore is more a library tool belt, but it provides a simple templating engine that works well for common use.
It is not clear what the transformation you are trying to achieve is, but I can tell you that you should not be using regex to achieve it! Transform your JSON into JavaScript objects using JSON.parse, transform the objects directly, then convert back to JSON via JSON.stringify.