web-dev-qa-db-fra.com

Envoi/Analyse de plusieurs objets JSON

J'ai un serveur Sinatra qui renvoie plusieurs objets JSON de la base de données en continu. Les objets ressembleraient à:

{"a": 1, "b": 2, "c": 3}
{"a": 4, "b": 5, "c": 6}
...

mais c'est JSON invalide. Je peux ajouter un hack au traitement des événements de Sinatra (en injectant manuellement les délimiteurs de tableau manquants) pour que la réponse ressemble à ceci:

[
{"a": 1, "b": 2, "c": 3}
, {"a": 4, "b": 5, "c": 6}
]

qui est valide JSON maintenant, mais cette technique est inélégante. Y at-il un moyen de faire ce côté client? En gros, ce que je veux, c'est qu'une fonction JavaScript lise une chaîne et consomme un objet JSON valide, puis me renvoie l'objet JSON et le reste de la chaîne, étant appelé de manière itérative jusqu'à ce que la chaîne entière soit consommée.

16
Kenny Peng

La fonction native JSON.parse() s'attend à ce que la chaîne entière soit un JSON valide. Je ne suis pas au courant d'un analyseur syntaxique qui consomme uniquement le premier objet valide comme vous le souhaitez. Et les gens devraient vraiment produire un JSON valide de toute façon.

Si vous savez qu'il y a un objet par ligne, vous pouvez simplement scinder la chaîne par ligne à l'aide de la fonction split() et analyser chaque ligne individuellement.

var str = '{"a": 1, "b": 2, "c": 3}\n'+
          '{"a": 4, "b": 5, "c": 6}';

var strLines = str.split("\n");


for (var i in strLines) {
  var obj = JSON.parse(strLines[i]);
  console.log(obj.a);
}

Vous pouvez également utiliser un peu de manipulation de chaîne pour transformer chaque ligne en un élément de tableau et analyser le tout.

str = "["+str.replace(/\n/g, ",")+"]";
JSON.parse(str);
14
Alex Jasmin

Je voudrais faire ceci:

var str = '{"a": 1, "b": 2, "c": 3}{"a": 4, "b": 5, "c": 6}';

var res = JSON.parse('[' + str.replace(/}{/g, '},{') + ']');

Modifier:

comme réponse sur le commentaire de Tremby

var str = '{"a": 1, "b": 2, "c": 3}{"a": 4, "b": 5, "c": 6}';

var res = JSON.parse('[' + str.replace(/}{(?=([^"]*"[^"]*")*[^"]*$)/g, '},{') + ']');
2
Chris

Si les chaînes JSON ne comportent qu'une seule ligne, vous pouvez utiliser l'une des méthodes suivantes:

var splitPoint = remainingData.indexOf("\n");
var currentJSONStr = splitPoint > -1 ? remainingData.substr(0, splitPoint) : remainingData;
remainingData =  splitPoint > -1 ? remainingData.substr(splitPoint+1) : '';
var dataObj = youJSONDecodeFuncOrEval(currentJSONStr);

Sinon, ignorez simplement ma réponse.

J'espère que ceci vous aide,
Alin


Note: j'ai essayé de remplir l'exigence

En gros, ce que je veux, c'est qu'une fonction JavaScript lise une chaîne et consomme un objet JSON valide, puis me renvoie l'objet JSON et le reste de la chaîne, étant appelé de manière itérative jusqu'à ce que la chaîne entière soit consommée.

c'est pourquoi je n'ai pas utilisé .split("\n").

2
Alin Purcaru

o.string est un objet json.

ajoutez une chaîne comme "new" à un tableau d'objets ou à plusieurs objets json.

pour par exemple:

json object----

{"id":2,"method":"listWirings","params":{"language":"anonymousLanguage","name":"mytest","working":"{\"modules\":[{\"config\":{\"position\":[186,59],\"xtype\":\"WireIt.ImageContainer\"},\"name\":\"Start\",\"value\":{}},{\"config\":{\"position\":[188,265],\"xtype\":\"WireIt.ImageContainer\"},\"name\":\"Stop\",\"value\":{}}],\"properties\":{\"description\":\"gfd\",\"name\":\"gf\"},\"wires\":[{\"src\":{\"moduleId\":0,\"terminal\":\"_OUTPUT\"},\"tgt\":{\"moduleId\":1,\"terminal\":\"StpIn\"}}]}"},"version":"json-rpc-2.0"}new

  var str = o.toString();
                var s = str.split("new");
                for (var i = 0; i < s.length-1; i++)
                {
                    var r = YAHOO.lang.JSON.parse(s[i]);
                }

espérons que cela permettra d’analyser plusieurs objets JSON.

1
Kishore Ganti

Ce n'est peut-être pas le plus efficace, mais devrait faire le travail.

var s = '{"a": 1, "b": 2, "c": 3}{"a": 4, "b": 5, "c": 6}';
var sTemp = "";
var aObjs = [];
for(var i=0; i<s.length; ++i)
{
    sTemp += s[i];
    if (s[i] == "}")
    {
        aObjs.Push(JSON.parse(sTemp));
        sTemp = "";
    }
}

Si vous savez qu'il y a un nouveau caractère de ligne entre les objets, cela devient beaucoup plus simple.

var sBad = '{"a": 1, "b": 2, "c": 3}\n{"a": 4, "b": 5, "c": 6}';
var sGood = "[" + sBad.replace(/\n/g, ",") + "]";
var aObjs = JSON.parse(sGood);
1
roto

J'ai écrit cette petite fonction JavaScript, qui vous permet d'analyser n'importe quelle chaîne d'objets Json. Cela fonctionne en passant à travers chaque caractère et en prenant note de la hiérarchie. L'avantage de cette solution est que vous pouvez obtenir tous les objets Json d'un texte sans savoir ce qui les sépare.

function evaluateJsonString(string){
    var start = string.indexOf('{');
    if(start == -1)
        return false;
    let hierarchy = 0;
    let characters = string.split('');
    let objects = [];
    for(var index = start; index < characters.length; index++){
        let char = characters[index];
        if(char == '{')
            hierarchy++;
        if(char == '}')
            hierarchy--;
        if(hierarchy == 0){
            objects.Push(JSON.parse(characters.slice(start, index + 1).join('')));
            index = start = index + characters.slice(index, characters.length).indexOf('{') - 1;
            if(start == -1)
                break;
        }
    }
    return objects;
}

let result = evaluateJsonString('This is {"name": "John", "age": 32, "hobbies": ["sport", "programming"]} He goes to {"name": "University", "director": {"name": "Peter", "age": 66, "hobbies": ["drinking coffee"]}}');

console.log(result);
0
LuSt

Aujourd'hui, j'ai écrit un petit module pour le faire et l'ai publié sur NPM sous la forme json-multi-parse . Le code est disponible sur Github .

Ma solution est simple, mais peut-être fragile, car elle repose sur le message d'erreur que JSON.parse renvoie lors de l'analyse d'une telle chaîne. Il utilise le numéro de position indiqué dans l'erreur (le numéro dans "Jeton inattendu {en JSON à la position xyz") pour tout analyser jusqu'à ce qu'il soit avant, puis recurse et tout ensuite.

Cependant, les accolades dans les chaînes ne le casseront pas, contrairement à d'autres solutions proposées ici.

Voici la version simple du code, qui fonctionnera dans Chrome et Node.

const ERROR_REGEX = /^Unexpected token { in JSON at position (\d+)$/;
function jsonMultiParse(input, acc = []) {
    if (input.trim().length === 0) {
        return acc;
    }
    try {
        acc.Push(JSON.parse(input));
        return acc;
    } catch (error) {
        const match = error.message.match(ERROR_REGEX);
        if (!match) {
            throw error;
        }
        const index = parseInt(match[1], 10);
        acc.Push(JSON.parse(input.substr(0, index)));
        return jsonMultiParse(input.substr(index), acc);
    }
}

Cela devient plus compliqué si vous voulez aussi supporter Firefox, ce qui donne son erreur dans un format donnant le numéro de ligne et le caractère dans cette ligne. Le module que j'ai lié ci-dessus gère ce cas.

0
tremby

Si le flux de données vous donne plusieurs objets JSON sur une ligne, vous devez les séparer en un tableau:

const str = '{"a": 1, "b": 2, "c": 3}\n' +
      '{"a": 4, "b": 5, "c": 6}' +
      '{"a": 7, "b": 8, "c": 9}';

const json = '[' + str.replace(/}\n?{/g, '},{') + ']';

JSON.parse(json).forEach((obj) => {
  console.log('a:', obj.a);
});
0
YodasWs