Ответ 1
Разбор JSON в браузере обычно выполняется с помощью только eval, но предшествует eval с регулярным выражением "lint", что должно сделать его безопасным для оценки JSON.
В википедии есть пример:
У меня очень большая строка JSON, которую мне нужно проанализировать с помощью JavaScript-браузера. Прямо сейчас, в нескольких браузерах, у меня заканчивается пространство стека. К сожалению, мой JSON может содержать пользовательские строки, поэтому я не могу использовать eval или иначе разрешать браузеру его анализировать.
Я просмотрел несколько стандартных JavaScript JSON-парсеров, и они являются рекурсивными. Интересно, знает ли кто-нибудь обозреватель JSON, который является безопасным и нерекурсивным. Я бы хотел, чтобы у него было меньше возможностей - у меня просто огромный массив объектов.
В качестве альтернативы, если кто-то знает о том, что может быть легко модифицировать, это тоже будет большой помощью.
EDIT: при ближайшем рассмотрении переполнение стека вызывается eval(), используемым внутри анализатора. Поэтому он должен быть рекурсивным.
Разбор JSON в браузере обычно выполняется с помощью только eval, но предшествует eval с регулярным выражением "lint", что должно сделать его безопасным для оценки JSON.
В википедии есть пример:
Если eval выбрасывает stackoverflow, вы можете использовать этот
http://code.google.com/p/json-sans-eval/
Парсер JSON, который вообще не использует eval().
Я написал json parsers, которые не являются рекурсивными на нескольких языках, но до сих пор не в javascript. Вместо того, чтобы быть рекурсивным, это использует локальный массив с именем stack. В actionscript это было значительно быстрее и эффективнее памяти, чем рекурсия, и я предполагаю, что javascript будет похож.
Эта реализация использует eval
только для цитируемых строк с обратными слэшами, как для оптимизации, так и для упрощения. Это можно было бы легко заменить обработкой строки из любого другого синтаксического анализатора. Код обработки перехода длинный и не связан с рекурсией.
Эта реализация не является строгой, по крайней мере, следующими способами. Он обрабатывает 8-битные символы как пробельные символы. Он позволяет вести цифры "+" и "0". Он позволяет задерживать "," в массивах и объектах. Он игнорирует ввод после первого результата. Итак, "[+09,] 2" возвращает [9] и игнорирует "2".
function parseJSON( inJSON ) {
var result;
var parent;
var string;
var depth = 0;
var stack = new Array();
var state = 0;
var began , place = 0 , limit = inJSON.length;
var letter;
while ( place < limit ) {
letter = inJSON.charCodeAt( place++ );
if ( letter <= 0x20 || letter >= 0x7F ) { // whitespace or control
} else if ( letter === 0x22 ) { // " string
var slash = 0;
var plain = true;
began = place - 1;
while ( place < limit ) {
letter = inJSON.charCodeAt( place++ );
if ( slash !== 0 ) {
slash = 0;
} else if ( letter === 0x5C ) { // \ escape
slash = 1;
plain = false;
} else if ( letter === 0x22 ) { // " string
if ( plain ) {
result = inJSON.substring( began + 1 , place - 1 );
} else {
string = inJSON.substring( began , place );
result = eval( string ); // eval to unescape
}
break;
}
}
} else if ( letter === 0x7B ) { // { object
stack[depth++] = state;
stack[depth++] = parent;
parent = new Object();
result = undefined;
state = letter;
} else if ( letter === 0x7D ) { // } object
if ( state === 0x3A ) {
parent[stack[--depth]] = result;
state = stack[--depth];
}
if ( state === 0x7B ) {
result = parent;
parent = stack[--depth];
state = stack[--depth];
} else {
// error got } expected state {
result = undefined;
break;
}
} else if ( letter === 0x5B ) { // [ array
stack[depth++] = state;
stack[depth++] = parent;
parent = new Array();
result = undefined;
state = letter;
} else if ( letter === 0x5D ) { // ] array
if ( state === 0x5B ) {
if ( undefined !== result ) parent.push( result );
result = parent;
parent = stack[--depth];
state = stack[--depth];
} else {
// error got ] expected state [
result = undefined;
break;
}
} else if ( letter === 0x2C ) { // , delimiter
if ( undefined === result ) {
// error got , expected previous value
break;
} else if ( state === 0x3A ) {
parent[stack[--depth]] = result;
state = stack[--depth];
result = undefined;
} else if ( state === 0x5B ) {
parent.push( result );
result = undefined;
} else {
// error got , expected state [ or :
result = undefined;
break;
}
} else if ( letter === 0x3A ) { // : assignment
if ( state === 0x7B ) {
// could verify result is string
stack[depth++] = state;
stack[depth++] = result;
state = letter;
result = undefined;
} else {
// error got : expected state {
result = undefined;
break;
}
} else {
if ( ( letter >= 0x30 && letter <= 0x39 ) || letter === 0x2B || letter === 0x2D || letter === 0x2E ) {
var exponent = -2;
var real = ( letter === 0x2E );
var digits = ( letter >= 0x30 && letter <= 0x39 ) ? 1 : 0;
began = place - 1;
while ( place < limit ) {
letter = inJSON.charCodeAt( place++ );
if ( letter >= 0x30 && letter <= 0x39 ) { // digit
digits += 1;
} else if ( letter === 0x2E ) { // .
if ( real ) break;
else real = true;
} else if ( letter === 0x45 || letter === 0x65 ) { // e E
if ( exponent > began || 0 === digits ) break;
else exponent = place - 1;
real = true;
} else if ( letter === 0x2B || letter === 0x2D ) { // + -
if ( place != exponent + 2 ) break;
} else {
break;
}
}
place -= 1;
string = inJSON.substring( began , place );
if ( 0 === digits ) break; // error expected digits
if ( real ) result = parseFloat( string );
else result = parseInt( string , 10 );
} else if ( letter === 0x6E && 'ull' === inJSON.substr( place , 3 ) ) {
result = null;
place += 3;
} else if ( letter === 0x74 && 'rue' === inJSON.substr( place , 3 ) ) {
result = true;
place += 3;
} else if ( letter === 0x66 && 'alse' === inJSON.substr( place , 4 ) ) {
result = false;
place += 4;
} else {
// error unrecognized literal
result = undefined;
break;
}
}
if ( 0 === depth ) break;
}
return result;
}
Я рекомендую вам разделить строку JSON на куски и принести их по требованию. Может быть, и AJAX, у вас может быть рецепт, который будет соответствовать вашим потребностям. Используя механизм "разделяй и властвуй", я думаю, вы все равно можете использовать общие методы разбора JSON.
Надеюсь, что это поможет,