JSON.stringify sin comillas en propiedades?

95

Estoy usando un servicio que usa un formato JSON incorrecto (sin comillas dobles alrededor de las propiedades). Entonces necesito enviar

{ name: "John Smith" } en vez de { "name": "John Smith" }

Este formato no se puede cambiar porque este no es mi servicio.

¿Alguien sabe de un enrutamiento de cadena para formatear un objeto JavaScript como el anterior?

jadent
fuente

Respuestas:

115

Esta sencilla solución de expresión regular funciona para eliminar las comillas de los nombres de propiedad JSON en la mayoría de los casos:

const object = { name: 'John Smith' };
const json = JSON.stringify(object);  // {"name":"John Smith"}
console.log(json);
const unquoted = json.replace(/"([^"]+)":/g, '$1:');
console.log(unquoted);  // {name:"John Smith"}

Caso extremo:

var json = '{ "name": "J\\":ohn Smith" }'
json.replace(/\\"/g,"\uFFFF");  // U+ FFFF
json = json.replace(/"([^"]+)":/g, '$1:').replace(/\uFFFF/g, '\\\"');
// '{ name: "J\":ohn Smith" }'

Un agradecimiento especial a Rob W por arreglarlo.

Limitaciones

En casos normales, la expresión regular antes mencionada funcionará, pero matemáticamente es imposible describir el formato JSON con una expresión regular de modo que funcione en todos los casos (contar el mismo número de llaves es imposible con expresiones regulares). Por lo tanto, tengo cree una nueva función para eliminar comillas analizando formalmente la cadena JSON a través de la función nativa y reserialícela:

function stringify(obj_from_json) {
    if (typeof obj_from_json !== "object" || Array.isArray(obj_from_json)){
        // not an object, stringify using native function
        return JSON.stringify(obj_from_json);
    }
    // Implements recursive object serialization according to JSON spec
    // but without quotes around the keys.
    let props = Object
        .keys(obj_from_json)
        .map(key => `${key}:${stringify(obj_from_json[key])}`)
        .join(",");
    return `{${props}}`;
}

Ejemplo: https://jsfiddle.net/DerekL/mssybp3k/

Derek 朕 會 功夫
fuente
3
Yo tampoco fui yo, pero debes leer la pregunta con atención. OP necesita codificar un objeto en json (roto), no analizarlo / evaluarlo.
Salman A
7
@Derek Este método no es confiable . Por ejemplo, tome esta entrada: {"foo":"e\":bar"}(JSON válido) se convierte en {foo:e:bar"}(...)!
Rob W
1
@Derek /\\\"/se puede simplificar a /\\"/. No olvide agregar la bandera global /\\"/g, o se romperá en cadenas con múltiples \". En cuanto al carácter aleatorio, nunca use un U + FFFF literal, en caso de que el editor se ahogue, sino una secuencia de escape. La expresión regular para revertir se convertiría en /\uFFFF/g.
Rob W
2
@Derek 朕 會 功夫 su expresión regular /\"([^(\")"]+)\":/gse puede simplificar /"([^"]+)":/g, consulte regex101.com/r/qnz0ld/2
tanguy_k
1
@endriu En ese caso, simplemente agregue una verificación adicional para valores nulos.
Derek 朕 會 功夫
18

Parece que este es un método simple de Object toString que está buscando.

En Node.js, esto se resuelve usando el objeto util y llamando a util.inspect (yourObject). Esto te dará todo lo que quieras. siga este enlace para obtener más opciones, incluida la profundidad de la aplicación del método. http://nodejs.org/api/util.html#util_util_inspect_object_options

Entonces, lo que está buscando es básicamente un inspector de objetos, no un convertidor JSON. El formato JSON especifica que todas las propiedades deben ir entre comillas dobles. Por lo tanto, no habrá convertidores JSON para hacer lo que desea, ya que simplemente no es un formato JSON. Especificaciones aquí: https://developer.mozilla.org/en-US/docs/Using_native_JSON

Objeto a la cadena o inspección es lo que necesita dependiendo del idioma de su servidor.

fino
fuente
1
¡Muchas gracias! Esto es exactamente lo que estaba buscando. Uso json para emitir datos a través del servidor ws a mi juego y lo creas o no, ¡no tener que lidiar con las comillas adicionales alrededor de los nombres de las propiedades ahorra una inmensa cantidad de datos! Solo para aclarar, también .toSource()funciona bien dentro de nodejs, pero no funciona con objetos en matrices. La utilinspección funciona para matrices y objetos en matrices, lo cual es maravilloso, me encanta.
NiCk Newman
3
util.inspect()Me funcionó de maravilla al escribir un objeto en una consulta de Neo4j, para establecer varios parámetros a la vez.
agm1984
1
Desde el enlace nodejs:> El método util.inspect () devuelve una representación de cadena del objeto que está destinado a la depuración. La salida de util.inspect puede cambiar en cualquier momento y no se debe depender de ella programáticamente.
Peter Roehlen
5

Puede ver el código fuente de un analizador creado por el que definió el formato JSON . Busque llamadas a funciones: estas rodean un valor entre comillas. Las claves se cotizan en las líneas 326 y 338 .json2.js quote

No incluya la biblioteca después de la modificación. En su lugar, solo tome la parte relevante ( stringify), o al menos reemplácela JSONcon otra cosa, por ejemplo. FAKEJSON.

Por ejemplo, un objeto FAKEJSONque solo define stringify: http://jsfiddle.net/PYudw/

Rob W
fuente
¿Por qué necesitaría una biblioteca adicional cuando puede hacerlo en JavaScript puro?
Derek 朕 會 功夫
Esta es una buena idea. Me desembolsar el repositorio, quite las comillas, y cambiar el nombre del objeto JSON a algo gracioso como FAILJSON para que quede claro que está no trabaja con el objeto JSON real, o JSON real.
RichardTowers
@Derek La biblioteca no debe incluirse en su totalidad. Solo toma la JSON.stringifyparte y elimina las comillas. Dado que la biblioteca es creada por quien definió JSON , podemos estar bastante seguros de que el resultado es un JSON muy válido.
Rob W
Parece que este es el mejor enfoque.
Derek 朕 會 功夫
Sí, de acuerdo con Derek. Aunque su sustituto funciona bien, me siento más seguro con el código de Crawford, sin faltarle el respeto a Derek jajaja. .toSource()funciona bien pero no incluye si su objeto está en la matriz, lo cual es un fastidio (y estoy en el nodo, por lo que la compatibilidad del navegador no es un problema: P), así que usaré este método gracias @RobW también, el enlace jsfiddle parece estar atascado en la página de carga :(
NiCk Newman
3

Intenta usar el servive con JSONP, supongo que lo ofrecen cuando usan este formato.

De lo contrario, envíeles un informe de error detallado que incluya una buena argumentación de por qué deben cumplir con el estándar. Cualquier otra solución que no sea eliminar el problema de origen no es una solución real.

Una solución rápida y sucia podría ser canalizar la cadena a través de una expresión regular antes de analizarla:

var obj = JSON.parse(str.replace(/(\{|,)\s*(.+?)\s*:/g, '$1 "$2":'));

O intenta ajustar un analizador JSON de JavaScript existente (como este ) si desea un análisis más sintáctico.

Bergi
fuente
3

Encontré un buen paquete de NPM para hacer precisamente esto:

https://www.npmjs.com/package/stringify-object

const stringify = require('stringify-object')

let prettyOutput = stringify(json);

Funciona bastante bien.

usuario1543276
fuente
1
Esta biblioteca no es recursiva.
corysimmons
2

YAML, que es un superconjunto de JSON, debería asimilar fácilmente la sintaxis heredada.

Pruebe el analizador y volcador YAML de JavaScript: http://nodeca.github.com/js-yaml/

usuario1649339
fuente
2

@Derek 朕 會 功夫 Gracias por compartir este método, me gustaría compartir mi código que también admite la secuenciación de una matriz de objetos.

export const stringifyObjectWithNoQuotesOnKeys = (obj_from_json) => {
    // In case of an array we'll stringify all objects.
    if (Array.isArray(obj_from_json)) {
        return `[${
                    obj_from_json
                        .map(obj => `${stringifyObjectWithNoQuotesOnKeys(obj)}`)
                        .join(",")
                }]` ;
    }
    // not an object, stringify using native function
    if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null){
        return JSON.stringify(obj_from_json);
    }
    // Implements recursive object serialization according to JSON spec
    // but without quotes around the keys.
    return `{${
            Object
                .keys(obj_from_json)
                .map(key => `${key}:${stringifyObjectWithNoQuotesOnKeys(obj_from_json[key])}`)
                .join(",")
            }}`;
};
Adel Bachene
fuente
1
También debería utilizar, JSON.stringifypor ejemplo, Date. También devuelve 'null'si obj_from_jsones nulo.
Far Dmitry
1
Acabo de arreglar los puntos planteados por @FarDmitry cambiando la segunda condición if para que se vea así:if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null)
Brunno Vodola Martins
2

Utilizar JSON5.stringify

JSON5 es un superconjunto de JSON que permite la sintaxis de ES5, incluidas las claves de propiedad sin comillas . La implementación de referencia JSON5 ( json5paquete npm ) proporciona un JSON5objeto que tiene los mismos métodos con los mismos argumentos y semántica que el JSONobjeto integrado .

Es muy probable que el servicio que está utilizando utilice esta biblioteca.

Iñigo
fuente