¿Cómo embellecer JSON.stringify () parcialmente?

Oct 01 2020

Los usuarios pueden descargar archivos JSON de nuestra aplicación, que quiero embellecer para una depuración más fácil que si todo estuviera en una línea. Sin embargo, esto aumenta el tamaño del archivo en casi un 40% incluso si la sangría es solo una pestaña o espacio.

Como compromiso, quiero excluir todos los valores con, por ejemplo, la clave "grande" del embellecimiento, así:

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

Traté de resolver esto usando el parámetro de reemplazo de JSON.stringify:

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

Sin embargo, los valores de las claves "grandes" terminan por escapar:

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>

¿Cómo puedo evitar que esto se escape o embellecer parcialmente JSON en JavaScript?

Respuestas

2 sbgib Oct 06 2020 at 16:00

Cada vez que llame JSON.stringifya un objeto (o parte de un objeto) más de una vez , terminará con marcas de habla escapadas. En este caso, después de que la JSON.stringifyfunción interna se haya aplicado dentro de la función de reemplazo, no hay forma de decirle a la JSON.stringifyfunción externa que no trate esa instancia como lo haría con cualquier otra cadena.

Entonces, creo que si su objetivo es "parcialmente" en cadena de un objeto, necesita escribir una función que implemente eso. Para este problema, sugeriría algo como esto:

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>

Aquí, se usa una función recursiva, que recorre las claves de un objeto y agrega el par clave-valor a una cadena, manejando diferentes tipos de datos. Si keyse encuentra en la excludematriz, entonces está en cadena.

Al recorrer las claves y aplicar condicionalmente JSON.stringifydonde sea necesario, está evitando efectivamente el problema anterior.

Estoy seguro de que puede haber casos extremos a tener en cuenta al escribir el JSON usted mismo en lugar de usar una función incorporada, pero podría adaptar algo como esto para satisfacer sus necesidades específicas.

EDITAR: respuesta actualizada para considerar mejor las matrices dentro del objeto.