jQuery.parseJSON lanza el error "Invalid JSON" debido a comillas simples escapadas en JSON


Estoy haciendo peticiones a mi servidor usando jQuery.post() y mi servidor está devolviendo objetos JSON (como { "var": "value", ... }). Sin embargo, si alguno de los valores contiene una comilla simple (correctamente escapado como \'), jQuery no puede analizar una cadena JSON válida. Este es un ejemplo de lo que quiero decir (hecho en la consola de Chrome):

data = "{ \"status\": \"success\", \"newHtml\": \"Hello \\\'x\" }";
eval("x = " + data); // { newHtml: "Hello 'x", status: "success" }

$.parseJSON(data); // Invalid JSON: { "status": "success", "newHtml": "Hello \'x" }

¿Es esto normal? ¿No hay forma de pasar correctamente una sola cita a través de JSON?

Author: Adaline Valentina Simonian, 2010-02-16

7 answers

De acuerdo con el diagrama de máquina de estados en el sitio web JSON, solo se permiten caracteres con comillas dobles escapadas, no comillas simples. Los caracteres de comilla simple no necesitan escaparse:

http://www.json.org/string.gif


Actualización - Más información para aquellos que están interesados:


Douglas Crockford no dice específicamente por qué la especificación JSON no permite comillas simples escapadas dentro de cadenas. Sin embargo, durante su discusión de JSON en Apéndice E de JavaScript: Las Partes Buenas , escribe:

Los objetivos de diseño de JSON debían ser mínimos, portátiles, textuales y un subconjunto de JavaScript. Cuanto menos tengamos que ponernos de acuerdo para interoperar, más fácilmente podremos interoperar.

Así que tal vez decidió permitir que solo se definieran cadenas usando comillas dobles, ya que esta es una regla menos en la que todas las implementaciones JSON deben estar de acuerdo. Como resultado, es imposible que un carácter de comilla simple dentro una cadena para terminar accidentalmente la cadena, porque por definición una cadena solo puede ser terminada por un carácter de comillas dobles. Por lo tanto, no es necesario permitir el escape de un carácter de comilla simple en la especificación formal.


Cavar un poco más profundo, Crockford org.json la implementación de JSON para Java es más permisible y permite caracteres de comillas simples:

Los textos producidos por los métodos toString se ajustan estrictamente a la Reglas de sintaxis JSON. Los constructores son más indulgentes en los textos que aceptarán:

...

  • Las cadenas pueden ser entrecomilladas con ' (comilla simple).

Esto es confirmado por el código fuente JSONTokener. El método nextString acepta caracteres de comillas simples escapadas y los trata como caracteres de comillas dobles:

public String nextString(char quote) throws JSONException {
    char c;
    StringBuffer sb = new StringBuffer();
    for (;;) {
        c = next();
        switch (c) {

        ...

        case '\\':
            c = this.next();
            switch (c) {

            ...

            case '"':
            case '\'':
            case '\\':
            case '/':
                sb.append(c);
                break;
        ...

En la parte superior del método hay un comentario informativo:

El formato JSON formal no permite cadenas entre comillas simples, pero una implementación puede aceptarlas.

Por lo tanto, algunas implementaciones aceptarán comillas simples, pero no debe confiar en esto. Muchas implementaciones populares son bastante restrictivas en este sentido y rechazarán JSON que contenga cadenas entre comillas simples y / o comillas simples escapadas.


Finalmente vincular esto a la pregunta original, jQuery.parseJSON primero intenta utilizar el analizador nativo de JSON del navegador o una biblioteca cargada como como json2.js donde sea aplicable (que en una nota lateral es la biblioteca en la que se basa la lógica de jQuery si JSON no está definida). Por lo tanto, jQuery solo puede ser tan permisivo como la implementación subyacente:

parseJSON: function( data ) {
    ...

    // Attempt to parse using the native JSON parser first
    if ( window.JSON && window.JSON.parse ) {
        return window.JSON.parse( data );
    }

    ...

    jQuery.error( "Invalid JSON: " + data );
},

Por lo que sé, estas implementaciones solo se adhieren a la especificación oficial de JSON y no aceptan comillas simples, por lo tanto, tampoco lo hace jQuery.

 321
Author: Justin Ethier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-08 23:17:20

Si necesita una comilla simple dentro de una cadena, ya que \ ' no está definido por la especificación, use \u0027 ver http://www.utf8-chartable.de / para todos ellos

Editar: por favor, disculpe mi mal uso de las palabras backsticks en los comentarios. Quise decir barra invertida. Mi punto aquí es que en el caso de que tenga cadenas anidadas dentro de otras cadenas, creo que puede ser más útil y legible usar unicode en lugar de muchas barras invertidas para escapar de una sola comilla. Si usted no está anidado sin embargo, realmente es más fácil poner una simple cita ahí.

 16
Author: slf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-13 02:56:18

Entiendo dónde radica el problema y cuando miro las especificaciones está claro que las comillas simples sin escaparse deben analizarse correctamente.

Estoy usando jQuery de jQuery.parseJSON función para analizar la cadena JSON, pero todavía obtener el error de análisis cuando hay una comilla simple en los datos que se prepara con json_encode.

Podría ser un error en mi implementación que se vea así (PHP - server side):

$data = array();

$elem = array();
$elem['name'] = 'Erik';
$elem['position'] = 'PHP Programmer';
$data[] = json_encode($elem);

$elem = array();
$elem['name'] = 'Carl';
$elem['position'] = 'C Programmer';
$data[] = json_encode($elem);

$jsonString = "[" . implode(", ", $data) . "]";

El paso final es que almaceno el JSON codificado string en una variable JS:

<script type="text/javascript">
employees = jQuery.parseJSON('<?=$marker; ?>');
</script>

Si utilizo "" en lugar de " todavía arroja un error.

SOLUCIÓN:

Lo único que funcionó para mí fue usar bitmask JSON_HEX_APOS para convertir las comillas simples de esta manera:

json_encode($tmp, JSON_HEX_APOS);

¿Hay otra forma de abordar este problema? ¿Mi código está mal escrito o mal escrito?

Gracias

 3
Author: Erik Čerpnjak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-27 07:17:37

Cuando está enviando una comilla simple en una consulta

empid = " T'via"
empid =escape(empid)

Cuando obtiene el valor incluyendo una comilla simple

var xxx  = request.QueryString("empid")
xxx= unscape(xxx)

Si desea buscar / insertar el valor que incluye una comilla simple en una consulta xxx=Replace(empid,"'","''")

 3
Author: BehranG BinA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-12 20:26:58

Se produce un problema similar usando CakePHP para generar un bloque de script JavaScript usando el nativo de PHP json_encode. $contractorCompanies contiene valores que tienen comillas simples y como se explicó anteriormente y se esperaba json_encode($contractorCompanies) no los escapa porque su JSON válido.

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".(json_encode($contractorCompanies)."' );"); ?>

Al agregar addslashes() alrededor de la cadena codificada en JSON, se escapan las comillas permitiendo que Cake / PHP haga eco del javascript correcto en el navegador. Los errores JS desaparecen.

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".addslashes(json_encode($contractorCompanies))."' );"); ?>
 2
Author: chopstik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-12 20:27:40

Interesante. ¿Cómo está generando su JSON en el extremo del servidor? ¿Está utilizando una función de biblioteca (como json_encode en PHP), o está construyendo la cadena JSON a mano?

Lo único que llama mi atención es el apóstrofo de escape (\'). Ya que está usando comillas dobles, como debería, no hay necesidad de escapar de las comillas simples. No puedo verificar si esa es la causa del error de jQuery, ya que aún no he actualizado a la versión 1.4.1.

 0
Author: Aistina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-16 18:49:42

Estaba tratando de guardar un objeto JSON de una solicitud XHR en un atributo data-* HTML5. Probé muchas de las soluciones anteriores sin éxito.

Lo que finalmente terminé haciendo fue reemplazar la comilla simple ' por su código &#39; usando una expresión regular después de que el método stringify() llame de la siguiente manera:

var productToString = JSON.stringify(productObject);
var quoteReplaced = productToString.replace(/'/g, "&#39;");
var anchor = '<a data-product=\'' + quoteReplaced + '\' href=\'#\'>' + productObject.name + '</a>';
// Here you can use the "anchor" variable to update your DOM element.
 0
Author: BoCyrill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-14 00:10:48