javascript $.getjson - jQuery.parseJSON lanza el error "Invalid JSON" debido a comillas simples escapadas en JSON




ejemplos parameters (7)

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

Lo que finalmente termino haciendo fue reemplazar la comilla simple ' con el código ' usando una expresión regular después del método stringify () llame de la siguiente manera:

var productToString = JSON.stringify(productObject);
var quoteReplaced = productToString.replace(/'/g, "'");
var anchor = '<a data-product=\'' + quoteReplaced + '\' href=\'#\'>' + productObject.name + '</a>';
// Here you can use the "anchor" variable to update your DOM element.

Estoy haciendo solicitudes 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 (escapada correctamente como \' ), jQuery no puede analizar una cadena JSON válida. Aquí hay 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" }

¿Esto es normal? ¿No hay manera de pasar correctamente una sola cita a través de JSON?


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

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

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

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

Entiendo dónde está el problema y cuando veo las especificaciones, queda claro que las comillas simples que no se escapan deben analizarse correctamente.

Estoy utilizando la función jQuery.parseJSON de jquery para analizar la cadena JSON, pero aún obtengo el error de análisis cuando hay una comilla simple en los datos preparados con json_encode.

¿Podría ser un error en mi implementación que se parece a esto (PHP - servidor):

$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 último paso es que almacene la cadena codificada JSON en una variable JS:

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

Si uso "" en lugar de '', todavía arroja un error.

SOLUCIÓN:

Lo único que me funcionó fue usar la máscara de bits 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 es incorrecto o está mal escrito?

Gracias


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

Lo único que me llama la atención es el apóstrofe de escape ( \' ). Viendo que está utilizando comillas dobles, como de hecho debería, no hay necesidad de escapar de comillas simples. No puedo comprobar si esa es la causa de su error jQuery, ya que todavía no he actualizado a la versión 1.4.1.


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

Edición: disculpe el mal uso de la palabra backticks en los comentarios. Quise decir barra invertida. Mi punto aquí es que, en caso de que haya cadenas anidadas dentro de otras cadenas, creo que puede ser más útil y legible utilizar Unicode en lugar de muchas barras invertidas para escapar de una sola cita. Sin embargo, si no está anidado, realmente es más fácil poner una simple cita en ese lugar.


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


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 las cadenas. Sin embargo, durante su discusión de JSON en el Apéndice E de JavaScript: The Good Parts , 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 estar de acuerdo para interoperar, más fácilmente podremos interoperar.

Por lo tanto, tal vez decidió que solo se pueden definir cadenas con 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 solo carácter de comillas dentro de una cadena termine accidentalmente la cadena, porque por definición una cadena solo puede terminar con un carácter de comillas dobles. Por lo tanto, no es necesario permitir que se escape un carácter de comillas simples en la especificación formal.

Al profundizar un poco más, la implementación de JSON para Java de Crockford es más permisible y permite caracteres de comillas simples:

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

...

  • Las cadenas se pueden citar con '(comilla simple).

Esto es confirmado por el código fuente de JSONTokener . El método nextString acepta caracteres de comillas simples escapados 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 en comillas simples, pero se permite que una implementación las acepte.

Así que algunas implementaciones aceptarán comillas simples, pero no debe confiar en esto. Muchas implementaciones populares son bastante restrictivas a este respecto y rechazarán JSON que contiene cadenas con comillas simples y / o comillas simples escapadas.

Finalmente, para vincular esto de nuevo a la pregunta original, jQuery.parseJSON primero intenta usar el analizador JSON nativo del navegador o una biblioteca cargada como json2.js donde corresponda (que en una nota es la biblioteca en la que se basa la lógica jQuery si JSON no está definido). 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 JSON oficial y no aceptan comillas simples, por lo tanto, tampoco jQuery.


Si search_term es un campo de entrada, es posible que desee obtener su valor.

var search_term = $(this).parents('.sub-middle-column').find('.search_horse').val();

Ahora mismo estás haciendo referencia a un objeto jQuery que contiene un elemento HTMLDom, pero creo que lo que quieres es la cadena dentro del elemento de entrada de búsqueda.





javascript jquery json