How to use $ .each loop through json code in JQuery
Thanks to the way my server-side script is outputting, I am getting multiple JSON objects. {jsonhere}{jsonhere1}{jsonhere2}{jsonhere3} etc..
They are not separated by anything. If I was doing division based on }{
I would lose those brackets. So is there an external loop I can put on top of a normal loop $.each
to make this work?
Thank,
ice
Rough algorithm:
Define a stack
Define an array
LOOP on each character in the string
IF the top item of the stack is a single or double quote THEN
LOOP through each character until you find a matching single or double quote, then pop it from the stack.
ELSE
IF "{", push onto the stack
IF "}" THEN
pop a "{" from the stack if it is on top
IF the stack is empty THEN //we just finished a full json object
Throw this json object into an array for later consumption
END IF
END IF
IF single-quote, push onto the stack
IF double-quote, push onto the stack
END IF
END LOOP
it is not JSON.
jQuery interprets JSON in a lazy way, calling eval () and hoping there is no "real" code there; therefore he will not agree with it. (I think you already know this).
Your only way out seems to be to treat it as a text string and use regular expressions to retrieve the data.
Below would be a valid JSON response:
[
{JSON},
{JSON},
{JSON},
{JSON}
]
Since your JSON is wrong, just fix it server side. The following code is a little more concise than suggested in the book called EndangeredMassa, and it avoids adding a comma between the curly braces enclosed in quotes. I'm not that good with RegEx to get my head around a single .replace ().
var string = "{\"key\":\"val}{ue\"}{'key':'val}{ue'}{ \"asdf\" : 500 }";
var result = string.match(/('.*?')|(".*?")|(\d+)|({)|(:)|(})/g);
var newstring = "";
for (var i in result) {
var next = parseInt(i) + 1;
if (next <= result.length) {
if (result[i] == "}" && result[next] == "{") {
newstring += "},";
}
else {
newstring += result[i];
}
}
}
Use the following to loop through JSON objects:
$.each(eval(newstring), function() {
//code that uses the JSON values
alert(this.value1);
alert(this.value2);
});
If you can't guarantee that any strings in the data won't contain "} {", you can't even split it up without parsing JSON, at least enough to keep track of whether you're in a string or not. For example, if you just split this:
{"foo": "}{", "bar": 42}
around "} {", you should get two invalid JSON objects instead of one.
If you know this will never happen, you can strip the curly braces and add "}" to every element except the last one and add "{" to the last element. I would only do this if there was absolutely no other way, because it's really fragile.
I managed to put together a working example! Save the following text as an html page. It seems to work well in IE7 and FF3. Let me know if you have any problems with this.
(I used jquery, but it really isn't needed at all.)
<html>
<head>
<script type="text/javascript" src="jquery-1.2.6.js"></script>
<script type="text/javascript">
function handleClick() {
var jsonStrs = parse();
var jsonObjs = [];
for(var j=0;j<jsonStrs.length;j++) jsonObjs.push( parseJSON(jsonStrs[j]) );
//jsonObjs now contains an array of json objects
document.getElementById('log').innerHTML = '';
displayResults(jsonObjs);
}
function displayResults(jsonObjs) {
for(var k=0; k<jsonObjs.length; k++) {
ShowObjProperties(jsonObjs[k]);
}
}
function ShowObjProperties(obj) {
var property, propCollection = "";
for(property in obj) {
propCollection += (property + ": " + obj[property] + "<br>");
}
log(propCollection);
}
function parseJSON(str) {
var x_result = null;
eval('x_result = ' + str);
return x_result;
}
function parse() {
//Setup
var out = $('#output');
var rawinput = $('#inputtext').val();
var input = rawinput.split('');
var stack = [];
stack.top = function() {
if (this.length == 0) return null;
return this[this.length-1];
}
var jsonStrs = [];
//Main Loop
var ch = '';
var top = '';
var cursor = 0;
var i = 0;
while (i<input.length) {
//Current Character
ch = input[i];
top = stack.top();
if(top == "'" || top == '"') { //Ignore the rest of the string
//You can add validation for possible unsafe javascript inside a string, here.
ch = input[++i];
while(ch != top) {
i++;
if(i>=input.length) {
alert('malformed string');
break;
}
ch = input[i];
}
stack.pop();
} else {
//You can add validation for unsafe javascript here.
if(ch == ' ') {
i++;
continue; // Ignore spaces
}
if(ch == "{" || ch == "'" || ch == '"') stack.push(ch);
if(ch == "}") {
if(top=="{") {
stack.pop();
} else {
alert('malformed string');
break;
}
if(stack.length == 0) {
var str = rawinput.substring(cursor, i+1)
jsonStrs.push(str);
cursor = i+1;
}
}
}
i++;
}
return jsonStrs;
}
function log(msg) {
document.getElementById('log').innerHTML += msg + '<br>';
}
</script>
</head>
<body>
<textarea id="inputtext" rows="5" cols="40" style="overflow:auto">{foo:'bar'}</textarea><br>
<button id="btnParse" onclick="handleClick();">Parse!</button><br /><br />
<div id="output">
</div>
<b>Results:</b>
<div id="log"></div>
</body>
</html>
It's not JSON, on the client side just fix your JSON code and you can "eval" it safely.
var jsonWrong = '{a:1}{a:2}{a:3}';
var jsonRight = jsonWrong.replace('}{', '},{');
var json = eval('('+jsonRight+')');