web-dev-qa-db-ja.com

JSON文字列化の深さを制限する

_JSON.stringify_(または類似の何か)を使用してオブジェクトを文字列化する場合、文字列化の深さを制限する方法があります。つまり、オブジェクトツリーの深いnレベルのみに移動し、その後に続くすべてを無視します(以上:そこにプレースホルダーを入れて、何かが取り除かれたことを示します)?

_JSON.stringify_がfunction (key, value)の形式の置換関数を取ることは知っていますが、置換プログラムに渡された現在のキーと値のペアの元のオブジェクトの深さを取得する方法が見つかりませんでした関数。

デフォルトのJSON.stringify実装でこれを行う方法はありますか?または、自分で文字列化を実装するだけのポイントに達しましたか?または、このオプションを持つことをお勧めできる別の文字列化ライブラリはありますか?

31
Joachim Kurz

サードパーティのライブラリを含めずに、最初のレベルでオブジェクトを文字列化したかったのですが、コードを増やしすぎませんでした。

あなたが同じものを探す場合、ここにそうするための簡単なワンライナーがあります:

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

トップレベルのオブジェクトはキーを持たないため、常に単純に返されますが、次のレベルの「数値」ではないものはすべて、文字列inclにキャストされます。配列の特別な場合、それ以外の場合はさらに公開されます。

この特別な配列のケースが気に入らない場合は、私が改善した古いソリューションを使用してください。

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

それでも、トップレベルでオブジェクトの代わりに配列を渡すと、両方のソリューションで機能します。

例:

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

以下は、組み込みのJSON.stringify()ルールを尊重しながら、深度も制限する関数です。

_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);
}
_

使い方:

  1. _build()は、ネストされたオブジェクトと配列を要求された深さに構築するために再帰的に呼び出されます。 JSON.stringify()は、組み込みルールを尊重するために各オブジェクトの直接のプロパティを反復するために使用されます。 'undefined'は常に内部置換プログラムから返されるため、JSONはまだ実際には構築されていません。内部置換が最初に呼び出されたとき、キーは空です(これは文字列化される項目です)。
  2. JSON.stringify()は、実際のJSONを生成するために最終結果で呼び出されます。

例:

_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": {}
  }
}
_

(循環参照を処理するバージョンについては、ここを参照してください: https://stackoverflow.com/a/57193345/1236397 -TypeScriptバージョンを含む)

1
James Wilkins

オブジェクトのディープクローンを作成し( low-dash などのライブラリを使用)、実行したいプルーニングを実行してから、それをJSON.stringifyに渡します。私はJSON.stringifyを再発明しようとはしません。それは間違った場所での努力です。

[EDIT]は、あなたが提案していたことをすでに誰かが行っているようです: JSON.stringify deep objects

ネイティブJSON.stringifyは常に高速で堅牢になるため、これはお勧めしません

[EDIT]ここに、あなたが望むことをしているように見えるライブラリがあります: http://philogb.github.io/jit/static /v20/Docs/files/Core/Core-js.html# $jit.json.Prune

1
Jack Allan