jQuery.parseJSON löst den Fehler "Ungültiger JSON" aus, da in JSON ein einfaches Anführungszeichen steht

202

Ich mache Anfragen an meinen Server mit jQuery.post()und mein Server gibt JSON-Objekte zurück (wie { "var": "value", ... }). Wenn jedoch einer der Werte ein einfaches Anführungszeichen enthält (ordnungsgemäß maskiert wie \'), kann jQuery eine ansonsten gültige JSON-Zeichenfolge nicht analysieren. Hier ist ein Beispiel für das, was ich meine ( in der Chrome-Konsole ):

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

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

Ist das normal? Gibt es keine Möglichkeit, ein einzelnes Angebot ordnungsgemäß über JSON zu übergeben?

Felix
quelle

Antworten:

325

Gemäß dem Zustandsmaschinendiagramm auf der JSON-Website sind nur maskierte doppelte Anführungszeichen zulässig, keine einfachen Anführungszeichen. Einfache Anführungszeichen müssen nicht maskiert werden:

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


Update - Weitere Informationen für Interessierte:


Douglas Crockford gibt nicht ausdrücklich an, warum die JSON-Spezifikation keine maskierten einfachen Anführungszeichen innerhalb von Zeichenfolgen zulässt. Während seiner Diskussion über JSON in Anhang E von JavaScript: The Good Parts schreibt er jedoch:

Die Designziele von JSON waren minimal, portabel, textuell und eine Teilmenge von JavaScript. Je weniger wir uns einigen müssen, um zusammenarbeiten zu können, desto leichter können wir zusammenarbeiten.

Vielleicht hat er beschlossen, Zeichenfolgen nur mit doppelten Anführungszeichen zu definieren, da dies eine Regel weniger ist, auf die sich alle JSON-Implementierungen einigen müssen. Infolgedessen kann ein einfaches Anführungszeichen innerhalb einer Zeichenfolge die Zeichenfolge nicht versehentlich beenden, da eine Zeichenfolge per Definition nur durch ein Zeichen in doppelten Anführungszeichen abgeschlossen werden kann. Daher ist es nicht erforderlich, das Entkommen eines einzelnen Anführungszeichens in der formalen Spezifikation zuzulassen.


Graben ein wenig tiefer, Crockford org.json ist Implementierung von JSON für Java mehr zulässig und tut Apostrophe ermöglichen:

Die von den toString-Methoden erstellten Texte entsprechen streng den JSON-Syntaxregeln. Die Konstrukteure sind in den Texten, die sie akzeptieren, verzeihender:

...

  • Zeichenfolgen können mit '(einfaches Anführungszeichen) zitiert werden.

Dies wird durch den JSONTokener- Quellcode bestätigt. Die nextStringMethode akzeptiert maskierte einfache Anführungszeichen und behandelt sie wie doppelte Anführungszeichen:

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

Am Anfang der Methode steht ein informativer Kommentar:

Das formale JSON-Format erlaubt keine Zeichenfolgen in einfachen Anführungszeichen, aber eine Implementierung kann sie akzeptieren.

Einige Implementierungen akzeptieren also einfache Anführungszeichen - aber Sie sollten sich nicht darauf verlassen. Viele gängige Implementierungen sind in dieser Hinsicht recht restriktiv und lehnen JSON ab, das Zeichenfolgen in einfachen Anführungszeichen und / oder einfache Anführungszeichen enthält.


Um dies mit der ursprünglichen Frage jQuery.parseJSONzu verknüpfen , versuchen Sie zunächst, den nativen JSON-Parser des Browsers oder gegebenenfalls eine geladene Bibliothek wie json2.js zu verwenden (auf einer Randnotiz steht die Bibliothek, auf der die jQuery-Logik basiert, wenn sie JSONnicht definiert ist). . Daher kann jQuery nur so tolerant sein wie die zugrunde liegende Implementierung:

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

Soweit ich weiß, entsprechen diese Implementierungen nur der offiziellen JSON-Spezifikation und akzeptieren keine einfachen Anführungszeichen, daher auch nicht jQuery.

Justin Ethier
quelle
4
UPDATE :: JQuery ist beim Pasing von JSON sehr restriktiv. Wenn Sie versuchen, alert ($. ParseJSON ("[\" Ciao \\ '\ "]")); es funktioniert nicht wegen dem, was Justin berichtet hat
daitangio
2
" Crockfords org.json-Implementierung von JSON für Java ist zulässiger und erlaubt einfache Anführungszeichen " # Das ist nur eine gute Praxis: Robustheitsprinzip
Duncan Jones
1
@ DuncanJones - Dieser Artikel bietet möglicherweise einen Einblick, warum keiner der Browser in Bezug auf JSON diesem Prinzip zu folgen scheint: joelonsoftware.com/items/2008/03/17.html
Justin Ethier
1
@JustinEthier, wie in dieser Antwort auf stackoverflow.com/a/25491642/759452 ausgeführt , sagt die JSON-Spezifikation tools.ietf.org/html/rfc7159Any character may be escaped , dies könnte erklären, warum bei einigen Implementierungen einfache Anführungszeichen maskiert werden könnten.
Adrien Be
1
@AdrienBe - Interessant ... aber bedeuteten sie, dass ein Zeichen maskiert werden kann, wenn es aus 4 hexadezimalen Ziffern besteht? Sowohl nach dem obigen Zustandsdiagramm als auch nach dem in Abschnitt 7 des RFC ist das Entkommen eines einzelnen Anführungszeichens wie geschrieben \'immer noch nicht zulässig. Es wäre schön, wenn der RFC in diesem Punkt expliziter wäre.
Justin Ethier
15

Wenn Sie ein einfaches Anführungszeichen innerhalb einer Zeichenfolge benötigen, da \ 'durch die Spezifikation nicht definiert ist, verwenden \u0027 Sie für alle die Angabe http://www.utf8-chartable.de/

edit: bitte entschuldige meinen missbrauch des wortes backticks in den kommentaren. Ich meinte Backslash. Mein Punkt hier ist, dass es für den Fall, dass Sie Zeichenfolgen in anderen Zeichenfolgen verschachtelt haben, nützlicher und lesbarer sein kann, Unicode anstelle vieler Backslashes zu verwenden, um einem einzelnen Anführungszeichen zu entgehen. Wenn Sie jedoch nicht verschachtelt sind, ist es wirklich einfacher, einfach ein altes Zitat einzufügen.

slf
quelle
29
Verwenden Sie einfach ein einfaches Anführungszeichen.
Jeff Kaufman
Manchmal ist es einfach einfacher, Unicode zu verwenden als Tonnen von Back-Ticks. Besonders im Inneren abwechselnder Back-Ticks.
SLF
3
Warum brauchst du Backticks? Wenn Sie eine Zeichenfolge wie "foo 'bar'" haben, lassen Sie die einfachen Anführungszeichen einfach frei.
Jeff Kaufman
3
genau das, wonach ich gesucht habe. Ich versuche, eine JSON-Zeichenfolge als JS-Zeichenfolgenvariable auf eine Seite zu schreiben und sie in einfache Anführungszeichen zu setzen. Sie wurde vorzeitig beendet, wenn ein Eigenschaftswert ein einfaches Anführungszeichen enthielt. Jetzt mache ich einfach ein json.Replace ("'", "\ u0027") im Code dahinter, bevor ich es auf die Seite schreibe.
Zack
@Zack Sie sollten JSON nicht in Anführungszeichen setzen. Wenn Sie eine Zeichenfolge aus einer vorhandenen JSON-Zeichenfolge benötigen, fügen Sie sie einfach erneut hinzu. In PHP ist dies der Ort, an var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>dem myEncodedJsondas Ergebnis eines vorherigen json_encodeAnführungszeichens liegt. Damit wird sichergestellt, dass kein einfaches Anführungszeichen angezeigt wird. Es wird lediglich eine große Zeichenfolge ausgegeben, die in doppelte Anführungszeichen eingeschlossen ist, sodass einfache Anführungszeichen nicht maskiert werden, sondern doppelte Anführungszeichen werden.
Juan Mendes
5

Ich verstehe, wo das Problem liegt, und wenn ich mir die Spezifikationen ansehe, ist klar, dass uneingeschränkte einfache Anführungszeichen korrekt analysiert werden sollten.

Ich verwende die jQuery.parseJSON-Funktion von jquery, um die JSON-Zeichenfolge zu analysieren, erhalte aber immer noch den Analysefehler, wenn die mit json_encode vorbereiteten Daten ein einfaches Anführungszeichen enthalten.

Könnte es ein Fehler in meiner Implementierung sein, der so aussieht (PHP - Serverseite):

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

Der letzte Schritt ist, dass ich die JSON-codierte Zeichenfolge in einer JS-Variablen speichere:

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

Wenn ich "" anstelle von '' verwende, wird immer noch ein Fehler ausgegeben.

LÖSUNG:

Das einzige, was für mich funktioniert hat, war die Verwendung der Bitmaske JSON_HEX_APOS, um die einfachen Anführungszeichen wie folgt zu konvertieren:

json_encode($tmp, JSON_HEX_APOS);

Gibt es eine andere Möglichkeit, dieses Problem anzugehen? Ist mein Code falsch oder schlecht geschrieben?

Vielen Dank

Erik Čerpnjak
quelle
'<? = $ marker; ?> 'das ist nicht gültig json. Die umgebenden Anführungszeichen werden vom Javascript-Interpreter "aufgefressen", sodass eine Zeichenfolge übrig bleibt, die mit einem <... beginnt. Was Sie wirklich ausprobieren wollten, war eine der folgenden: jQuery.parseJSON ('"<? = $ Marker;?>" '); jQuery.parseJSON ("" <? = $ marker;?> ""); Gemäß der Spezifikation müssen JSON-Zeichenfolgen doppelte Anführungszeichen verwenden, aber Javascript ist das egal. Sie haben entweder eine einfache Anführungszeichen-Javascript-Zeichenfolge oder ein doppeltes Anführungszeichen. Wenn Sie jedoch die letztere verwenden, müssen Sie ihnen alle Zeichen setzen Verwendung von doppelten Anführungszeichen innerhalb der Zeichenfolge.
Chris Cogdon
3

Wenn Sie ein einzelnes Angebot in einer Abfrage senden

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

Wenn Sie den Wert einschließlich eines einfachen Anführungszeichens erhalten

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

Wenn Sie den Wert suchen / einfügen möchten, der ein einfaches Anführungszeichen in einer Abfrage enthält xxx=Replace(empid,"'","''")

BehranG BinA
quelle
1
Es ist jedoch nicht erforderlich, sich einem einzelnen Anführungszeichen zu entziehen, wenn Sie es als Teil einer JSON-Zeichenfolge übergeben ...
Justin Ethier
2

Ein ähnliches Problem mit CakePHP zur Ausgabe eines JavaScript-Skriptblocks mit PHPs native json_encode. $contractorCompaniesenthält Werte mit einfachen Anführungszeichen und wird, wie oben erläutert und erwartet json_encode($contractorCompanies), nicht ausgeblendet, da es sich um einen gültigen JSON handelt.

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

Durch Hinzufügen von addslashes () um die JSON-codierte Zeichenfolge werden die Anführungszeichen entfernt, sodass Cake / PHP das richtige Javascript an den Browser zurücksenden kann. JS-Fehler verschwinden.

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

Ich habe versucht, ein JSON-Objekt aus einer XHR-Anforderung in einem HTML5-Daten- * -Attribut zu speichern. Ich habe viele der oben genannten Lösungen ohne Erfolg ausprobiert.

Am Ende habe ich das einfache Anführungszeichen 'durch &#39;den regulären Code durch einen regulären Ausdruck ersetzt, nachdem die Methode stringify () Folgendes aufgerufen hat:

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.
BoCyrill
quelle
0

Interessant. Wie generieren Sie Ihren JSON auf der Serverseite? Verwenden Sie eine Bibliotheksfunktion (z. B. json_encodein PHP) oder erstellen Sie die JSON-Zeichenfolge von Hand?

Das einzige, was meine Aufmerksamkeit auf sich zieht, ist der Fluchtapostroph ( \'). Da Sie doppelte Anführungszeichen verwenden, wie Sie es tatsächlich sollten, müssen Sie sich einfachen Anführungszeichen nicht entziehen. Ich kann nicht überprüfen, ob dies tatsächlich die Ursache für Ihren jQuery-Fehler ist, da ich selbst noch nicht auf Version 1.4.1 aktualisiert habe.

Aistina
quelle
Ich benutze eine Bibliothek in PHP, um das JSON-Objekt zu generieren - ich habe es irgendwie versäumt, das aufzuschreiben. Vielen Dank für den Hinweis.
Erik Čerpnjak