javascript - jQuery.parseJSON, JSON içindeki kaçışlı tek tırnak nedeniyle “Geçersiz JSON” hatası veriyor
Ben sunucuma jQuery.post() kullanarak istekler yapıyorum ve sunucum JSON nesneleri döndürüyor (örneğin { "var": "value", ... }). Ancak, değerlerden herhangi biri tek tırnak içeriyorsa (doğru şekilde kaçırılmış olarak \' gibi), jQuery normalde geçerli olan bir JSON dizgesini ayrıştıramıyor. Şu konuda ne demek istediğimi gösterecek bir örnek (Chrome’un konsolunda yapılmış):
data = "{ \"status\": \"success\", \"newHtml\": \"Hello "'x\" }";
eval("x = " + data); // { newHtml: "Hello 'x", status: "success" }
$.parseJSON(data); // Invalid JSON: { "status": "success", "newHtml": "Hello \'x" }
Bu normal mi? JSON aracılığıyla tek tırnak doğru bir şekilde geçmenin yolu yok mu?
Cevap #1
JSON web sitesindeki durum makinesi diyagramına göre, yalnızca kaçış karakteri eklenmiş çift tırnak karakterlerine izin verilir, tek tırnaklara değil. Tek tırnak karakterlerinin kaçış karakteri eklenmesine gerek yoktur:
Güncelleme - İlgilenenler için daha fazla bilgi:
Douglas Crockford, JSON spesifikasyonunun neden dizeler içinde kaçış karakterli tek tırnaklara izin vermediğini özellikle belirtmiyor. Ancak, JavaScript: The Good Parts kitabının Ek E bölümünde JSON'u tartışırken şunları yazıyor:
JSON'un tasarım hedefleri minimal, taşınabilir, metinsel ve JavaScript'in bir alt kümesi olmaktı. Birbirimizle çalışabilmek için üzerinde anlaşmamız gereken ne kadar az şey olursa, o kadar kolay bir şekilde birlikte çalışabiliriz.
Bu yüzden belki de sadece çift tırnak kullanılarak dizelerin tanımlanmasına izin vermeye karar verdi, çünkü bu, tüm JSON uygulamalarının hemfikir olması gereken bir kural daha az demek. Sonuç olarak, bir dizedeki tek tırnak karakterinin kazara diziyi sonlandırması imkansızdır, çünkü tanım gereği bir dize yalnızca çift tırnak karakteri ile sonlandırılabilir. Bu nedenle, resmi spesifikasyonda tek tırnak karakterinin kaçışına izin vermeye gerek yoktur.
Biraz daha derine inersek, Crockford'un Java için org.json JSON uygulaması daha izin verici ve tek tırnak karakterlerine izin veriyor:
toString yöntemleri tarafından üretilen metinler JSON sözdizimi kurallarına sıkı sıkıya uyar. Yapıcılar, kabul edecekleri metinlerde daha hoşgörülüdür:
...
- Dizeler ' (tek tırnak) ile tırnak içine alınabilir.
Bu, JSONTokener kaynak kodu tarafından doğrulanmaktadır. nextString yöntemi, kaçış karakteri eklenmiş tek tırnak karakterlerini kabul eder ve onları çift tırnak karakterleri gibi ele alır:
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;
...
Yöntemin en üstünde bilgilendirici bir yorum vardır:
Resmî JSON formatı tek tırnak içindeki dizeleri izin vermez, ancak bir uygulamanın bunları kabul etmesine izin verilir.
Yani bazı uygulamalar tek tırnak kabul edecektir - ancak buna güvenmemelisiniz. Birçok popüler uygulama bu konuda oldukça kısıtlayıcıdır ve tek tırnaklı dizeler ve/veya kaçışlı tek tırnak içeren JSON'u reddedecektir.
Son olarak, bunu orijinal soruya bağlamak için, jQuery.parseJSON öncelikle tarayıcının yerleşik JSON ayrıştırıcısını veya uygulanabilir olduğu yerlerde json2.js gibi yüklenmiş bir kütüphaneyi kullanmayı dener (bu arada, JSON tanımlı değilse jQuery mantığının dayandığı kütüphane budur). Bu nedenle, jQuery yalnızca o temel uygulamanın izin verdiği kadar esnek olabilir:
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 );
},
Bildiğim kadarıyla bu uygulamalar yalnızca resmi JSON spesifikasyonuna uymaktadır ve tek tırnakları kabul etmemektedir, dolayısıyla jQuery de kabul etmez.
Cevap #2
Eğer bir string içinde tek tırnak işaretine ihtiyacınız varsa, çünkü \' spesifikasyon tarafından tanımlanmamıştır, \u0027 kullanın hepsi için http://www.utf8-chartable.de/ adresine bakın
düzenleme: lütfen yorumlarda backticks kelimesini yanlış kullandığım için özür dilerim. Aslında backslash demek istedim. Buradaki noktam, eğer bir dizenin içinde başka dizeler varsa, tek bir tırnak işaretini kaçırmak için çok sayıda backslash kullanmak yerine unicode kullanmanın daha faydalı ve okunabilir olabileceğini düşünüyorum. Ancak, eğer dize iç içe değilse, gerçekten de içine sade bir tırnak koymak daha kolaydır.
