Wie kann man JSON.stringify () teilweise verschönern?

Oct 01 2020

Benutzer können JSON-Dateien von unserer Anwendung herunterladen, die ich zum einfacheren Debuggen verschönern möchte, als wenn alles in einer Zeile steht. Dies erhöht jedoch die Dateigröße um fast 40%, selbst wenn der Einzug nur eine einzelne Registerkarte oder ein Leerzeichen ist.

Als Kompromiss möchte ich alle Werte mit zB dem Schlüssel "groß" von der Verschönerung ausschließen, wie folgt:

{
 "small":
 {
  "a": 1,
  "b": 2,
  "large": {"a":1,"b":2,"c":3,"d":"the \"large\" object should not be prettified"} 
 },
  "large": {"a":1,"b":2,"c":3,"d":"the \"large\" object should not be prettified"}
}

Ich habe versucht, dies mit dem Ersetzerparameter von JSON.stringify zu lösen :

JSON.stringify(data,(key,value)=>key==="large"?JSON.stringify(data):value,'\t');

Die Werte für die "großen" Schlüssel werden jedoch maskiert:

data = 
{
     "small":
     {
      "a": 1,
      "b": [2,3,4,5],
      "large": {"myarray":[1,2,3,4],"b":2,"c":3,"d":"the \"large\" object should not be prettified"} 
     },
      "large": {"a":1,"b":2,"c":3,"d":"the \"large\" object should not be prettified"}
    }
    
 const json =  JSON.stringify(data,(key,value)=>key==="large"?JSON.stringify(data):value,'\t');
 document.getElementById("json").innerText = json;
<html>
<body>
<pre id="json">
</pre>
</body>
</html>

Wie kann ich verhindern, dass dies geschieht, oder JSON in JavaScript auf andere Weise teilweise verschönern?

Antworten

2 sbgib Oct 06 2020 at 16:00

Jedes Mal, wenn Sie JSON.stringifyein Objekt (oder einen Teil eines Objekts) mehr als einmal aufrufen , erhalten Sie maskierte Sprachmarkierungen. In diesem Fall JSON.stringifygibt es keine Möglichkeit, die äußere JSON.stringifyFunktion anzuweisen, diese Instanz nicht wie jede andere Zeichenfolge zu behandeln , nachdem die innere Funktion innerhalb der Ersetzungsfunktion angewendet wurde .

Ich denke also, wenn Ihr Ziel darin besteht, ein Objekt teilweise zu stringifizieren, müssen Sie eine Funktion schreiben, die dies implementiert. Für dieses Problem würde ich Folgendes vorschlagen:

data = {
  "small": {
    "a": 1,
    "b": [2, 3, 4, 5],
    "c": [2, {"test":"example"}, [4,4], 5],
    "large": {
      "myarray": [1, 2, 3, 4],
      "b": 2,
      "c": 3,
      "d": "the \"large\" object should not be prettified"
    }
  },
  "large": {
    "a": 1,
    "b": 2,
    "c": 3,
    "d": "the \"large\" object should not be prettified"
  }
}

function print(obj, exclude, space) {
  let recur = (obj, spacing, inarray) => {
    let txt = '';

    if (inarray) {
      if (Array.isArray(obj)) {        
        txt += '[';

        for(let i=0;i<obj.length;i++) {
          txt += recur(obj[i], spacing + space, true);
        };

        txt = txt.substr(0, Math.max(1,txt.length - 2)) + ']';
        
      } else if (typeof obj === 'object' && obj !== null) {
        txt += '{' + recur(obj, spacing + space, false) + '\n' + spacing + '}';
      } else if (typeof obj === 'string') {
        txt += obj.replaceAll(/\"/g, '\\"') + '"';
      } else {
        txt += obj;
      };
      
      return txt + ', ';
      
    } else {
      for (let key of Object.keys(obj)) {
        if (exclude.indexOf(key) !== -1) {
          txt += '\n' + spacing + '"' + key + '": ' + JSON.stringify(obj[key]);
        } else if (Array.isArray(obj[key])) {
          txt += '\n' + spacing + '"' + key + '": [';
          
          for(let i=0;i<obj[key].length;i++) {
            txt += recur(obj[key][i], spacing + space, true);
          };
          
          txt = txt.substr(0, Math.max(1,txt.length - 2)) + ']';
          
        } else if (typeof obj[key] === 'object' && obj[key] !== null) {
          txt += '\n' + spacing + '"' + key + '": {' + recur(obj[key], spacing + space, false) + '\n' + spacing + '}';
        } else if (typeof obj[key] === 'string') {
          txt += '\n' + spacing + '"' + key + '": "' + obj[key].replaceAll(/\"/g, '\\"') + '"';
        } else {
          txt += '\n' + spacing + '"' + key + '": ' + obj[key];
        };
        
        txt += ',';
      };
      
      return txt.substr(0, txt.length - 1);
    };

  };
  return (Array.isArray(obj) ? '[' + recur(obj, space, true) + '\n' + ']' : '{' + recur(obj, space, false) + '\n' + '}');
};

document.getElementById("json").innerText = print(data, ['large'], '\t');
<html>
<body>
  <pre id="json">
</pre>
</body>
</html>

Hier wird eine rekursive Funktion verwendet, die die Schlüssel eines Objekts durchläuft und das Schlüssel-Wert-Paar an eine Zeichenfolge anfügt, die für verschiedene Datentypen behandelt wird. Wenn das keyim excludeArray gefunden wird, wird es stringifiziert.

Indem Sie die Schlüssel durchlaufen und JSON.stringifybei Bedarf bedingt anwenden , vermeiden Sie das oben genannte Problem effektiv.

Ich bin mir sicher, dass es Randfälle geben muss, auf die Sie achten müssen, wenn Sie den JSON selbst schreiben, anstatt eine integrierte Funktion zu verwenden, aber Sie können so etwas an Ihre spezifischen Anforderungen anpassen.

BEARBEITEN: Antwort aktualisiert, um Arrays innerhalb des Objekts besser zu berücksichtigen.