jQuery.parseJSON lance une erreur "JSON invalide" due à une citation unique échappée dans JSON

je fais des requêtes à mon serveur en utilisant jQuery.post() et mon serveur renvoie des objets JSON (comme { "var": "value", ... } ). Cependant, si l'une des valeurs contient une seule citation (correctement échappée comme ' ), jQuery ne parvient pas à analyser une chaîne JSON valide. Voici un exemple de ce que je veux dire ( fait 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 aucun moyen de transmettre correctement une seule citation via JSON?

196
demandé sur Adaline Valentina Simonian 2010-02-16 21:39:18

7 réponses

selon le diagramme de la machine d'état sur le site de JSON , seuls les caractères à double guillemets échappés sont autorisés, pas les guillemets simples. Des guillemets simples n'ont pas besoin d'être échappé:

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



mise à jour - plus d'informations pour ceux qui sont intéressés:


Douglas Crockford ne précisez pourquoi la spécification JSON ne permet pas les guillemets échappés dans les chaînes. Cependant, lors de sa discussion de 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. Le moins que nous devons nous entendre sur d'interagir, plus facilement on peut interagir.

alors peut - être qu'il décidé de n'autoriser que les chaînes à être définies en utilisant des guillemets, car c'est une règle de moins que toutes les implémentations JSON doivent accepter. En conséquence, il est impossible pour un seul caractère de guillemet dans une chaîne accidentellement mettre fin à la chaîne, parce que, par définition, une chaîne ne peut être résilié par un guillemet. Il n'est donc pas nécessaire de permettre l'échappatoire d'un seul caractère de citation dans la spécification formelle.


Creusant un peu plus, Crockford's org.json l'implémentation de JSON pour Java est plus admissible et ne permet des caractères de citation simple:

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 cordes peuvent être citées avec" (apostrophe.)

ceci est confirmé par le code source JSONTokener . La méthode nextString accepte les caractères de guillemets simples échappés et les traite comme des caractères de guillemets doubles:

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;
        ...

au début de la méthode est un commentaire informatif:

le format JSON formel ne permet pas de chaînes en guillemets simples, mais une implémentation est autorisés à les accepter.

ainsi, certaines implémentations accepteront des guillemets simples - mais vous ne devriez pas vous y fier. De nombreuses implémentations populaires sont assez restrictives à cet égard et rejetteront JSON qui contient des chaines de caractères simples et/ou des guillemets simples échappés.


enfin, pour lier ce retour à la question originale, jQuery.parseJSON premières tentatives d'utiliser le JSON natif du navigateur analyseur ou une bibliothèque chargée telle que json2.js le cas échéant (qui sur une note latérale est la bibliothèque sur laquelle la logique jQuery est basée si JSON n'est pas défini). Ainsi, le jQuery ne peut être aussi permissif que la mise en œuvre 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 );
},

pour autant que je sache, ces implémentations ne respectent que la spécification officielle de JSON et n'acceptent pas les devis simples, donc jQuery non plus.

321
répondu Justin Ethier 2012-03-08 23:17:20

Si vous avez besoin d'une offre unique à l'intérieur d'une chaîne, depuis \' est pas défini par la spécification, utiliser \u0027 voir http://www.utf8-chartable.de/ pour tous

edit: s'il vous plaît excuser mon mauvais usage de la parole backticks dans les commentaires. Je voulais barre oblique inverse. Mon point ici est que dans le cas où vous avez imbriqué des chaînes à l'intérieur d'autres chaînes, je pense qu'il peut être plus utile et lisible d'utiliser unicode au lieu de beaucoup de backslashes pour échapper à un simple citation. Si vous n'êtes pas imbriquée cependant, il est vraiment plus facile de mettre juste un simple vieux devis.

16
répondu slf 2015-11-13 02:56:18

je comprends où se trouve le problème et quand je regarde les spécifications il est clair que les citations simples non escapadrées doivent être interprétées correctement.

j'utilise le jQuery de jquery.parseJSON fonction pour analyser la chaîne de caractères JSON, mais obtient toujours l'erreur de parse quand il y a une seule citation dans les données qui est préparé avec json_encode.

pourrait - il S'agir d'une erreur dans mon implémentation qui ressemble à ceci (côté serveur PHP):

$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 " Il y a toujours une erreur.

SOLUTION:

la seule chose qui a fonctionné pour moi était d'utiliser bitmask JSON_HEX_APOS pour convertir les guillemets simples comme ceci:

json_encode($tmp, JSON_HEX_APOS);

y a-t-il un autre moyen d'aborder cette question? Est mon code erroné ou mal écrit?

Merci

3
répondu Erik Čerpnjak 2015-01-27 07:17:37

lorsque vous envoyez un seul devis dans une requête

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

quand vous obtenez la valeur en incluant une seule soumission

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

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

3
répondu BehranG BinA 2018-06-12 20:26:58

frappant un problème similaire en utilisant CakePHP pour produire un bloc de script JavaScript en utilisant le natif de PHP json_encode . $contractorCompanies contient des valeurs qui ont des guillemets simples et comme expliqué ci-dessus et attendu json_encode($contractorCompanies) ne leur échappe pas parce que son JSON valide.

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

en ajoutant addslashes() autour de la chaîne encodée par JSON, vous échappez alors aux guillemets qui permettent à Cake / PHP d'afficher le javascript correct sur le navigateur. Les erreurs JS disparaître.

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".addslashes(json_encode($contractorCompanies))."' );"); ?>
2
répondu chopstik 2018-06-12 20:27:40

intéressant. Comment générez-vous votre JSON du côté du serveur? Utilisez-vous une fonction de bibliothèque (comme json_encode en PHP), ou construisez-vous la chaîne JSON à la main?

la seule chose qui retient mon attention est l'apostrophe d'évasion ( \' ). Puisque vous utilisez des guillemets doubles, comme vous le devriez, il n'est pas nécessaire d'échapper aux guillemets simples. Je ne peux pas vérifier si c'est bien la cause de votre erreur jQuery, car je n'ai pas mis à jour vers la version 1.4.1 moi-même encore.

0
répondu Aistina 2010-02-16 18:49:42

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

ce que j'ai finalement fait était de remplacer la simple citation ' par le code it &#39; en utilisant un regex après l'appel de méthode stringify () 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
répondu BoCyrill 2017-04-14 00:10:48