jQuery.parseJSONは、JSON内のエスケープされた単一引用符が原因で「無効なJSON」エラーをスローします


202

を使用してサーバーにリクエストを送信しjQuery.post()ていますが、サーバーがJSONオブジェクト(など{ "var": "value", ... })を返しています。ただし、いずれかの値に単一引用符が含まれている場合(正しくのようにエスケープされている場合\')、jQueryはそれ以外の場合は有効なJSON文字列の解析に失敗します。これが私の意味の例です(Chromeのコンソールで行われます):

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

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

これは正常ですか?JSONを介して単一引用符を正しく渡す方法はありませんか?

回答:


325

JSON Webサイトの状態マシン図によると、エスケープされた二重引用符文字のみが許可され、単一引用符は許可されていません。一重引用符はエスケープする必要はありません:

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


更新 -興味のある方のための詳細情報:


Douglas Crockfordは、JSON仕様で文字列内のエスケープされた単一引用符が許可されない理由を具体的に述べていません。ただし、JavaScript:The Good Partsの付録EでのJSONの議論中に、彼は次のように書いています。

JSONの設計目標は、最小限、移植可能、テキスト、およびJavaScriptのサブセットでした。相互運用するために同意する必要が少ないほど、相互運用が容易になります。

そのため、おそらくすべてのJSON実装が同意しなければならないルールが1つ少ないため、二重引用符を使用して文字列のみを定義できるようにすることにしました。その結果、定義によって文字列は二重引用符文字でしか終了できないため、文字列内の単一引用符文字が誤って文字列を終了することはありません。したがって、正式な仕様で単一引用符文字をエスケープすることを許可する必要はありません。


少し深く掘る、クロックフォードのorg.jsonの Java用のJSONの実装は、より許容されかつ、単一引用符を許可します:

toStringメソッドによって生成されるテキストは、JSON構文規則に厳密に準拠しています。コンストラクターは、受け入れるテキストでより寛容です。

...

  • 文字列は '(一重引用符)で囲むことができます。

これは、JSONTokenerソースコードによって確認されます。このnextStringメソッドは、エスケープされた単一引用符文字を受け入れ、それらを二重引用符文字と同様に扱います。

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

メソッドの上部には、有益なコメントがあります。

正式なJSON形式では文字列を一重引用符で囲むことはできませんが、実装ではそれらを受け入れることができます。

そのため、一部の実装では単一引用符を受け入れますが、これに依存するべきではありません。多くの一般的な実装では、この点に関して非常に制限があり、単一引用符で囲まれた文字列やエスケープされた単一引用符を含むJSONを拒否します。


最後に、これを元の質問に結び付けるために、jQuery.parseJSONまずブラウザのネイティブJSONパーサーまたはjson2.jsなどのロードされたライブラリ(該当する場合、jQueryロジックがJSON定義されていない場合にjQueryロジックが使用するライブラリ)を使用しようとします。。したがって、jQueryは、その基礎となる実装と同じくらい寛容でしかありません。

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

私の知る限り、これらの実装は公式のJSON仕様にのみ準拠しており、単一引用符を受け入れないため、jQueryも受け入れません。


4
更新:: JSONを渡す場合、JQueryは非常に制限されます。alert($。parseJSON( "[\" Ciao \\ '\ "]"));を試した場合 ジャスティンが報告したことが原因で機能しない
daitangio

2
" Java向けJSONのCrockfordのorg.json実装はより許容され、単一引用符文字を許可します "#これはちょうど良い習慣です:堅牢性の原則
Duncan Jones

1
@DuncanJones-この記事は、JSONに関してどの
Justin

1
この回答stackoverflow.com/a/25491642/759452で指摘されている@JustinEthierのJSON仕様tools.ietf.org/html/rfc7159Any character may be escaped、これにより、一部の実装で単一引用符をエスケープできる理由が説明される場合があります。
Adrien Be

1
@AdrienBe-興味深い...しかし、4桁の16進数で構成されている場合、エスケープされる可能性がある文字を意味するのでしょうか。上記の状態図とRFCのセクション7の状態図の両方によれば、記述されている単一引用符のエスケープ\'はまだ許可されていません。この点についてRFCがより明確であるとよいでしょう。
Justin Ethier 2014

15

文字列内で単一引用符が必要な場合は、\ 'が仕様で定義されていないため、http: //www.utf8-chartable.de/を使用して\u0027 ください

編集:コメント内のバッククォートという単語の誤用を許してください。私はバックスラッシュを意味しました。ここでの私のポイントは、他の文字列内に文字列をネストしている場合、単一引用符をエスケープするために多くのバックスラッシュの代わりにUnicodeを使用する方がより便利で読みやすいと思います。ネストされていない場合は、単純に古い引用をそこに入れる方が本当に簡単です。


29
いいえ。単なる一重引用符を使用してください。
ジェフカウフマン

時には、大量のバックティックよりもユニコードを使用するほうがはるかに簡単です。特に、交互のバックティックの内側にある場合。
slf 2012

3
なぜバックティックが必要なのですか?「foo 'bar'」のような文字列がある場合は、一重引用符をエスケープしないでください。
Jeff Kaufman、

3
まさに私が探していたもの。私はjson文字列をjs文字列varとしてページに書き込み、一重引用符で囲もうとしています。プロパティ値に単一引用符が含まれていると、早期に終了していました。ページに書き込む前に、コードビハインドでjson.Replace( "'"、 "\ u0027")を実行するだけです。
Zack

@Zack JSONを引用符で囲まないでください。既存のJSON文字列から文字列が必要な場合は、もう一度文字列化します。PHPでは、それは前の結果のvar jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>場所になりますそれはあなたの単一引用符をエスケープします、実際には、それは二重引用符で囲まれた大きな文字列を出力するだけなので、単一引用符はエスケープされませんが、二重引用符です意志。myEncodedJsonjson_encode
ファンメンデス

5

問題がどこにあるかを理解し、仕様を見ると、エスケープされていない単一引用符が正しく解析される必要があることは明らかです。

jqueryのjQuery.parseJSON関数を使用してJSON文字列を解析していますが、json_encodeで準備されたデータに単一引用符があると解析エラーが発生します。

これは私の実装の次のような間違いかもしれません(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) . "]";

最後のステップは、JSONエンコードされた文字列をJS変数に格納することです。

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

''の代わりに ""を使用しても、エラーがスローされます。

解決:

私にとってうまくいった唯一のことは、ビットマスクJSON_HEX_APOSを使用して、次のように単一引用符を変換することでした:

json_encode($tmp, JSON_HEX_APOS);

この問題に取り組む別の方法はありますか?私のコードは間違っているか、不十分に書かれていますか?

ありがとう


'<?= $ marker; ?> 'これは有効なjsonではありません。周囲の引用符は、JavaScriptインタープリターによって「食い尽くされ」、<...で始まる文字列が残ります。実際に試してみたかったのは、次のいずれかです。jQuery.parseJSON( '"<?= $ marker;?>" '); jQuery.parseJSON( "\" <?= $ marker;?> \ ""); 仕様によると、json文字列は二重引用符を使用する必要がありますが、javascriptは関係ありません。そのため、単一引用符のjavascript文字列または二重引用符のいずれかを使用しますが、後者を使用する場合は、すべてをエスケープする必要があります。文字列内での二重引用符の使用。
Chris Cogdon、2015年

3

クエリで単一引用符を送信する場合

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

一重引用符を含む値を取得する場合

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

クエリで単一引用符を含む値を検索/挿入する場合 xxx=Replace(empid,"'","''")


1
しかし、JSON文字列の一部として渡すときに、単一引用符をエスケープする必要はありません...
Justin Ethier

2

PHPのネイティブを使用してJavaScriptスクリプトブロックを出力するためにCakePHPを使用して同様の問題を打つjson_encode$contractorCompanies単一引用符が含まれている値が含まれ、上記で説明されているとおり、json_encode($contractorCompanies)JSONが有効であるため、これらの値はエスケープされません。

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

JSONエンコードされた文字列の周りにaddlashes()を追加することにより、引用符をエスケープして、Cake / PHPがブラウザに正しいJavaScriptをエコーできるようにします。JSエラーが消えます。

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

1

XHRリクエストのJSONオブジェクトをHTML5 data- *属性に保存しようとしました。上記の解決策の多くを試したが成功しなかった。

最終的に私がやったことは、stringify()メソッドが次のように呼び出した後、正規表現を使用'して一重引用符をコードで置き換えることでした&#39;

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

面白い。サーバー側でJSONをどのように生成していますか?ライブラリ関数(json_encodePHP など)を使用していますか、それとも手動でJSON文字列を構築していますか?

私の注意を引くのは、エスケープアポストロフィ(\')だけです。二重引用符を使用していることを確認すると、実際にそうであるように、単一引用符をエスケープする必要はありません。私がまだバージョン1.4.1に更新していないので、それが本当にjQueryエラーの原因であるかどうかは確認できません。


私はPHPのライブラリーを使用してJSONオブジェクトを生成しています。ご指摘いただきありがとうございます。
ErikČerpnjak15年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.