web-dev-qa-db-fra.com

jQuery.parseJSON génère une erreur "Invalid JSON" en raison d'un guillemet simple échappé en JSON

Je fais des requêtes sur mon serveur en utilisant jQuery.post() et mon serveur renvoie des objets JSON (comme { "var": "value", ... }). Cependant, si l'une des valeurs contient un guillemet simple (correctement échappé, comme \'), jQuery ne parvient pas à analyser une chaîne JSON sinon valide. Voici un exemple de ce que je veux dire ( dans la console 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" }

Est-ce normal? N'y a-t-il pas moyen de passer correctement un seul devis via JSON?

199
Felix

Selon le diagramme de la machine à états sur le site Web JSON , seuls les caractères entre guillemets échappés sont autorisés, et non les guillemets simples. Les caractères entre guillemets n'ont pas besoin d'être échappés:

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


Mettre à jour - Plus d'informations pour ceux qui sont intéressés:


Douglas Crockford n'indique pas spécifiquement pourquoi la spécification JSON n'autorise pas les guillemets simples échappés dans les chaînes. Cependant, lors de sa discussion sur JSON dans Annexe E de JavaScript: Les bonnes parties }, il écrit:

Les objectifs de conception de JSON devaient être minimes, portables, textuels et un sous-ensemble de JavaScript. Moins on doit s'entendre pour interopérer, plus on peut interagir facilement.

Alors peut-être a-t-il décidé d'autoriser uniquement la définition des chaînes à l'aide de guillemets puisqu'il s'agit d'une règle de moins sur laquelle toutes les implémentations JSON doivent s'accorder. En conséquence, il est impossible qu'un seul caractère de citation dans une chaîne termine accidentellement la chaîne car, par définition, une chaîne ne peut être terminée que par un caractère de double citation. Par conséquent, il n'est pas nécessaire d'autoriser l'échappement d'un seul caractère de citation dans la spécification formelle.


Pour aller un peu plus loin, l’implémentation de JSON pour Java par org.json de Crockford est plus permise et est-ce que autorise les caractères entre guillemets simples:

Les textes produits par les méthodes toString sont strictement conformes aux règles de syntaxe JSON. Les constructeurs sont plus indulgents dans les textes qu’ils accepteront:

...

  • Les chaînes peuvent être citées avec '(guillemet simple).

Ceci est confirmé par le code source JSONTokener . La méthode nextString accepte les caractères entre guillemets et les traite comme des caractères entre guillemets:

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 haut de la méthode se trouve un commentaire informatif:

Le format JSON formel n'autorise pas les chaînes entre guillemets simples, mais une implémentation est autorisée à les accepter.

Ainsi, certaines implémentations accepteront les guillemets simples - mais vous ne devriez pas vous en fier. De nombreuses implémentations populaires sont assez restrictives à cet égard et rejetteront JSON qui contient des chaînes entre guillemets simples et/ou des guillemets simples échappés.


Enfin, pour relier cette question à la question initiale, jQuery.parseJSON essaie d’abord d’utiliser l’analyseur JSON natif du navigateur ou une bibliothèque chargée telle que json2.js le cas échéant (qui la bibliothèque sur laquelle la logique jQuery est basée si JSON n’est pas définie). Ainsi, jQuery ne peut être aussi permissif que cette implémentation sous-jacente:

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 );
},

Autant que je sache, ces implémentations ne font que adhérer à la spécification JSON officielle et n'acceptent pas les guillemets simples. Par conséquent, jQuery non plus.

323
Justin Ethier

Si vous avez besoin d'un guillemet simple dans une chaîne,\'n'étant pas défini par la spécification, utilisez \u0027 voir http://www.utf8-chartable.de/ pour chacun d'eux.

edit: veuillez excuser mon mauvais usage des backticks de Word dans les commentaires. Je voulais dire backslash. Mon point ici est que, si vous avez des chaînes imbriquées dans d'autres chaînes, je pense qu'il peut être plus utile et lisible d'utiliser Unicode au lieu de nombreuses barres obliques inverses pour échapper à un seul guillemet. Si vous n'êtes pas imbriqué, il est cependant plus facile de simplement y mettre une citation ancienne et simple.

16
slf

Lorsque vous envoyez un seul devis dans une requête

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

Lorsque vous obtenez la valeur, y compris un seul devis

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

Si vous souhaitez rechercher/insérer la valeur qui inclut un seul devis dans une requête xxx=Replace(empid,"'","''")

3
BehranG BinA

Je comprends où réside le problème et, lorsque je regarde les spécifications, il est clair que les guillemets simples non échappés doivent être analysés correctement.

J'utilise la fonction jQuery.parseJSON de jquery pour analyser la chaîne JSON, mais j'obtiens toujours l'erreur d'analyse lorsqu'un seul guillemet est dans les données préparées avec json_encode.

Cela pourrait-il être une erreur dans mon implémentation qui ressemble à ceci (PHP - côté serveur):

$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) . "]";

La dernière étape est que je stocke la chaîne encodée JSON dans une variable JS:

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

Si j'utilise "" au lieu de "", cela génère quand même une erreur.

SOLUTION:

La seule chose qui a fonctionné pour moi a été d'utiliser le masque de masque JSON_HEX_APOS pour convertir les guillemets simples comme ceci:

json_encode($tmp, JSON_HEX_APOS);

Existe-t-il un autre moyen de s'attaquer à ce problème? Mon code est-il incorrect ou mal écrit?

Merci

3
Erik Čerpnjak

Résoudre un problème similaire en utilisant CakePHP pour générer un bloc de script JavaScript en utilisant le json_encode natif de PHP. $contractorCompanies contient des valeurs qui ont des guillemets simples et, comme expliqué ci-dessus, la fonction json_encode($contractorCompanies) attendue ne les échappe pas, car son code JSON valide.

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

En ajoutant addedlashes () autour de la chaîne codée JSON, vous échappez les guillemets, ce qui permet à Cake/PHP d'envoyer le bon javascript au navigateur. Les erreurs JS disparaissent.

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

J'essayais de sauvegarder un objet JSON d'une requête XHR dans un attribut HTML5 data- *. J'ai essayé plusieurs des solutions ci-dessus sans succès.

Ce que je me suis finalement décidé à faire est de remplacer le guillemet simple ' par ce code &#39; en utilisant une expression rationnelle après que la méthode stringify () a appelé de la manière suivante: 

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
BoCyrill

Intéressant. Comment générez-vous votre JSON sur le serveur? Utilisez-vous une fonction de bibliothèque (telle que json_encode en PHP) ou créez-vous la chaîne JSON à la main?

La seule chose qui attire mon attention est l'apostrophe d'échappement (\'). Comme vous utilisez des guillemets doubles, comme il se doit, il n’est pas nécessaire d’échapper aux guillemets simples. Je ne peux pas vérifier si c'est effectivement la cause de votre erreur jQuery, car je n'ai pas encore mis à jour la version 1.4.1.

0
Aistina