Reputation: 4157
I have a node app from which I get some data. I have gone through other questions asked on SO..but Im unable to figure this out. I need to access the value of result . The code below shows the exact response I get from server. None of the methods described in other answers like JSON.parse() etc seem to work.
[{
query: {
"parameter1": "12",
"parameter2": "13",
"parameter3": 25
}
result: 6.58443
}]
EDIT : As mentioned in the comments below, unfortunately I cant fix this on the server side(Comes from an external source). I have to deal with this broken JSON on my end and extract the value of result. EDIT 2 : Yes, there are multiple arrays like this. The content and comma part doesnt change. They are listed one after the other.
Upvotes: 0
Views: 819
Reputation: 24788
Purely for illustrative purposes, the below code "rewrites" JSON that is missing commas into JSON that has commas in the appropriate places. The advantage of using this over a replace
or a regular expression is that this code guarantees that string literals are handled correctly:
const LEX_EXPR = (
'('
+ '"(?:\\\\(?:["\\\\/bfnrt]|u[a-fA-F0-9]{4})|[^"])*"|'
+ '-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|'
+ '(?:true|false|null)'
+ ')|'
+ '([{\\[])|'
+ '([}\\]])|'
+ '([:,])|'
+ '(\\s+)|'
+ '(.)'
)
function lex(string) {
let tokens = []
let expr = new RegExp(LEX_EXPR, 'mguy')
let match = expr.exec(string)
while(match !== null) {
let [
value,
atom,
begin, end, sep,
whitespace,
junk
] = match
let type
if (atom != null) {
type = "atom"
} else if (begin != null) {
type = "begin"
} else if (end != null) {
type = "end"
} else if (sep != null) {
type = "sep"
} else if (whitespace != null) {
type = "whitespace"
} else {
// junk. ignore or raise exception
throw `Invalid character: ${junk}`
}
tokens.push({ type, value })
match = expr.exec(string)
}
return tokens
}
function shouldInsertComma(prev, cur) {
if (!prev || !cur) {
return false
}
if (prev.type == "begin" || prev.type == "sep") {
return false
}
return cur.type == "begin" || cur.type == "atom"
}
function rewrite(tokens) {
let out = []
let prevNonWhitespace = null
for (let i = 0; i < tokens.length; i++) {
let cur = tokens[i]
if (cur.type !== "whitespace") {
if (shouldInsertComma(prevNonWhitespace, cur)) {
out.push({ type: "sep", value: "," })
}
prevNonWhitespace = cur
}
out.push(cur)
}
return out
}
function joinTokens(tokens) {
return tokens.map(({ value }) => value).join('')
}
const invalid = `
{
"foo": {
"bat": "bing}"
"boo": "bug"
}
"result": "yes"
}
`
const rewritten = joinTokens(rewrite(lex(invalid)))
console.log(JSON.parse(rewritten)) // { foo: { bat: 'bing}', boo: 'bug' }, result: 'yes' }
Upvotes: 0
Reputation: 4157
The suggestions provided above..all point to a hacky way of solving this. The only way to solve this issue was with the help of good old Regex expressions. To my surprise..even though there are lots of libraries to handle JSON parsing etc, to solve edge cases(Common when dealing with small clients or unreliable data source), there is no library which can handle this scenario. @Bitifet's answer is what solves this problem..with regex.
Upvotes: 0
Reputation: 3659
Despite the fact you can't receive that data though any library function that expects JSON like jQuery $.ajax() with dataType='json'
option (you should use dataType="text"
in this case to avoid premature error being triggered I mean).
...you obviously need to fix JSON syntax before parsing it (as I understood you already know).
If it is what you are asking for, your best bet is a regular expression search and replace.
If you know you won't get things such as '{bracket: "}"}' it is pretty simple:
Example:
var wrong = `
[{
"query": {
"parameter1": "12",
"parameter2": "13",
"parameter3": 25
}
"result": 6.58443
}]
`;
var good = wrong.replace(/}(?!\s*[,}\]])/g, '},');
var json = JSON.parse(good);
console.log(json);
This is the simplest example that fixes the input you provided.
Even though it does not fix the same problem after an end of array (']') and, most importantly, if it were fixed it (or simply the string ended with '}' instead of ']' it would added an extra ',' at the end messing up things again.
A more polite approach solving beferementioned issues is to replace the var good = ...
row in previous code with this one:
var good = wrong.replace(/(}|])(?!\s*[,}\]])/g, '$1,')
.replace(/,\s*$/, '')
;
Now, you have a valid json object so accessing any property in it is pretty obvious. For example, json[0].result
is what you asked for.
On the other hand, if you can have brackets inside literal strings, it will be much more difficult (even not impossible). But I figure out it would hardly be the case...
Upvotes: 2
Reputation: 2886
what you can do is to encapsulate your result with back-ticks to have a (valid) string literal, then get result with any method you want, for example a matching regex :
var arr = `[{
"query": {
"parameter1": "12",
"parameter2": "13",
"parameter3": 25
}
"result": 6.58443
}]`;
var match = arr.match(/("result": )(\d*.\d*)/);
console.log(match[2]);
Upvotes: 0