web-dev-qa-db-fra.com

Limiter la profondeur de stringification JSON

Lorsque vous limitez un objet à l'aide de JSON.stringify (Ou quelque chose de similaire) est là un moyen de limiter la profondeur de stringification, c'est-à-dire aller n niveaux profondément dans l'arborescence d'objets et ignorer tout ce qui vient après cela (ou mieux: mettre des espaces réservés là-bas, indiquant que quelque chose a été laissé de côté)?

Je sais que JSON.stringify Prend une fonction de remplacement du formulaire function (key, value) _ Mais je n'ai pas trouvé de moyen d'obtenir la profondeur dans l'objet d'origine de la valeur de la valeur de la clé-valeur actuelle. Fonction de remplacement.

Y a-t-il un moyen de le faire avec la mise en œuvre par défaut JSON.Stringify? Ou j'ai atteint un point où je devrais simplement mettre en œuvre le stringification moi-même? Ou existe-t-il une autre bibliothèque de stringification que vous pouvez recommander avec cette option?

31
Joachim Kurz

Je voulais régler un objet au premier niveau sans inclure une bibliothèque tierce/trop de code.

Si vous recherchez la même chose, voici une doublure rapide pour le faire:

var json = JSON.stringify(obj, function (k, v) { return k && v && typeof v !== "number" ? (Array.isArray(v) ? "[object Array]" : "" + v) : v; });

L'objet de niveau supérieur n'aura aucune clé. Il est donc toujours simplement retourné, mais tout ce qui n'est pas un "nombre" au niveau suivant sera coulé sur une chaîne incl. Un cas particulier pour les tableaux, sinon ceux-ci seraient exposés plus en plus.

Si vous n'aimez pas ce cas de tableau spécial, utilisez ma vieille solution, que j'ai aussi amélioré:

var json = JSON.stringify(obj, function (k, v) { return k && v && typeof v !== "number" ? "" + v : v; }); // will expose arrays as strings.

Le passage d'un tableau au lieu d'un objet dans le niveau supérieur fonctionnera néanmoins dans les deux solutions.

Exemples :

var obj = {
  keyA: "test",
  keyB: undefined,
  keyC: 42,
  keyD: [12, "test123", undefined]
}
obj.keyD.Push(obj);
obj.keyE = obj;

var arr = [12, "test123", undefined];
arr.Push(arr);

var f = function (k, v) { return k && v && typeof v !== "number" ? (Array.isArray(v) ? "[object Array]" : "" + v) : v; };
var f2 = function (k, v) { return k && v && typeof v !== "number" ? "" + v : v; };

console.log("object:", JSON.stringify(obj, f));
console.log("array:", JSON.stringify(arr, f));
console.log("");
console.log("with array string cast, so the array gets exposed:");
console.log("object:", JSON.stringify(obj, f2));
console.log("array:", JSON.stringify(arr, f2));
10
modiX

Voici une fonction qui respecte les règles intégrées JSON.stringify() _ tout en limitant la profondeur:

function stringify(val, depth, replacer, space) {
    depth = isNaN(+depth) ? 1 : depth;
    function _build(key, val, depth, o, a) { // (JSON.stringify() has it's own rules, which we respect here by using it for property iteration)
        return !val || typeof val != 'object' ? val : (a=Array.isArray(val), JSON.stringify(val, function(k,v){ if (a || depth > 0) { if (replacer) v=replacer(k,v); if (!k) return (a=Array.isArray(v),val=v); !o && (o=a?[]:{}); o[k] = _build(k, v, a?depth:depth-1); } }), o||{});
    }
    return JSON.stringify(_build('', val, depth), null, space);
}

Comment ça fonctionne:

  1. _build() s'appelle récursivement pour construire les objets et les tableaux imbriqués à la profondeur demandée. JSON.stringify() est utilisé pour itérer sur les propriétés immédiates de chaque objet pour respecter les règles intégrées. "Undefined" est toujours renvoyé du remplaceur interne afin qu'aucun JSON soit encore construit. Gardez à l'esprit, la première fois que le remplaceur interne est appelé la clé est vide (qui est l'élément à régler).
  2. JSON.stringify() est appelé le résultat final pour produire le JSON réel.

Exemple:

var value={a:[12,2,{y:3,z:{q:1}}],s:'!',o:{x:1,o2:{y:1}}};

console.log(stringify(value, 0, null, 2));
console.log(stringify(value, 1, null, 2));
console.log(stringify(value, 2, null, 2));

{}

{
  "a": [
    12,
    2,
    {}
  ],
  "s": "!",
  "o": {}
}

{
  "a": [
    12,
    2,
    {
      "y": 3,
      "z": {}
    }
  ],
  "s": "!",
  "o": {
    "x": 1,
    "o2": {}
  }
}

(pour une version qui gère des références cycliques, voir ici: https://stackoverflow.com/a/57193345/1236397 - inclut une version dossée)

1
James Wilkins

Faites un clone profond de votre objet (avec une bibliothèque telle que bas tiret ), faites ce que vous voulez faire et ensuite le transmettre à JSON.Stringify. Je n'essaierais pas de réinventer JSON.Stringify, c'est un effort au mauvais endroit.

[modifier] On dirait que quelqu'un a déjà fait ce que vous suggérez: JSON.Stringify ciblez des objets profonds

Je ne recommanderais pas cela cependant parce que le Json.stringify natif va toujours être plus rapide et plus robuste

[modifier] Voici une bibliothèque qui semble faire ce que vous voulez: http://philogb.github.io/jit/statique /v20/docs/files/core/core-js.html# $jit.json.prune

1
Jack Allan