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 , допускаються лише символи подвійної цитати, а не одноцитати. Символи однієї цитати не потрібно уникати:

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


Оновлення - Більше інформації для зацікавлених:


Дуглас Крокфорд конкретно не говорить, чому специфікація JSON не дозволяє уникнути одинарних лапок у рядках. Однак під час свого обговорення JSON у Додатку E JavaScript: "Гарні частини" він пише:

Цілі дизайну JSON повинні були бути мінімальними, портативними, текстовими та підмножиною JavaScript. Чим менше нам потрібно узгодити для взаємодії, тим легше ми можемо взаємодіяти.

Тому, можливо, він вирішив дозволити визначати лише рядки за допомогою подвійних лапок, оскільки це одне менше правило, з яким повинні погоджуватися всі реалізації JSON. Як результат, неможливо, щоб один символ цитата в рядку випадково припинив рядок, оскільки за визначенням рядок може бути припинений лише символом подвійної лапки. Отже, не потрібно допускати виходу одного символу цитати у формальній специфікації.


Риття трохи глибше, Крокфорд в org.json реалізація JSON для Java є більш допустимим і робить дозволяють одиничні лапки:

Тексти, створені методами 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 може бути настільки ж дозвільним, як і основна реалізація:

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
ОНОВЛЕННЯ :: JQuery дуже обмежуючий при вставці JSON. Якщо ви спробуєте попередити ($. ParseJSON ("[\" Ciao \\ '\ "]")); це не працює через те, що повідомив Джастін
daitangio

2
" Реалізація JSON для Java Crockford в org.json є більш допустимою і дозволяє однозначно використовувати цитати " # Це просто хороша практика: принцип стійкості
Duncan Jones

1
@DuncanJones - Ця стаття може дати зрозуміти, чому жоден із браузерів не дотримується цього принципу щодо JSON: joelonsoftware.com/items/2008/03/17.html
Джастін Етьє

1
@JustinEthier, на що вказує ця відповідь stackoverflow.com/a/25491642/759452 , JSON spec tools.ietf.org/html/rfc7159 говорить Any character may be escaped, що це може пояснити, чому деяка реалізація дозволить уникати одинарних лапок.
Адрієн Бе

1
@AdrienBe - Цікаво ... але чи означали вони, що будь-який символ може уникнути, якщо він складається з 4-х шістнадцяткових цифр? Відповідно до діаграми стану, наведеної вище, та тієї, що в розділі 7 RFC, уникнення єдиної цитати, як написано \', все ще не допускається. Було б добре, якби RFC був більш чітким щодо цього.
Джастін Етьє

15

Якщо вам потрібна одна цитата всередині рядка, оскільки \ 'не визначено специфікацією, скористайтеся \u0027 див. Http://www.utf8-chartable.de/ для всіх них

редагувати: пробачте, будь ласка, моє неправильне використання задніх слів у коментарях. Я мав на увазі зворотний нахил. Моя думка тут полягає в тому, що якщо ви вклали рядки в інші рядки, я думаю, що може бути кориснішим і зручнішим читати використання Unicode замість великої кількості зворотних косих рисок, щоб уникнути єдиної цитати. Якщо ви не вкладені, проте справді простіше просто помістити туди стару цитату.


29
Ні. Просто використовуйте просту цитату.
Джефф Кауфман

Іноді просто використовувати простіший унікод просто, ніж тонну зворотних кліщів. Особливо, коли всередині чергуються зворотні кліщі.
slf

3
Навіщо вам потрібні бекстіки? Якщо у вас є такий рядок, як "foo 'bar" ", ви просто залишите нецільові цитати.
Джефф Кауфман

3
саме те, що я шукав. Я намагаюся записати рядок json на сторінку як js рядок рядка і долучити її до одиничних лапок, і вона закінчувалася рано, коли значення властивості містило в ній одну цитату. Тепер я просто роблю json.Replace ("'", "\ u0027") у коді позаду перед тим, як записати його на сторінку.
Зак

@Zack Не слід додавати JSON цитатами. Якщо вам потрібна рядок із існуючої рядка JSON, просто ще раз її змініть. в PHP, який був би var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>де myEncodedJsonрезультат попереднього , json_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);

Чи є інший спосіб вирішення цього питання? Невірний чи погано написаний мій код?

Дякую


'<? = $ маркер; ?> 'це недійсний json. Навколишні лапки "з'їдаються" інтерпретатором javascript, залишаючи рядок, що починається з <... те, що ви дійсно хотіли спробувати, було будь-яким із них: jQuery.parseJSON ('"<? = $ Marker;?>" '); jQuery.parseJSON ("\" <? = $ маркер;?> \ ""); Згідно з специфікацією, рядки json повинні використовувати подвійні лапки, але javascript не хвилює, так що у вас є або рядок javascript з одною цитатою, або подвійна цитата, але якщо ви використовуєте останню, вам доведеться їм уникнути всіх використання подвійних лапок всередині рядка.
Кріс Когдон

3

Коли ви надсилаєте одну запит у запиті

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

Коли ви отримуєте значення, включаючи одну пропозицію

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

Якщо ви хочете шукати / вставити значення, яке включає в себе одну запит у запиті xxx=Replace(empid,"'","''")


1
Але не потрібно уникати жодної цитати, передаючи її як частину рядка JSON ...
Джастін Етьє

2

Уражає аналогічну проблему за допомогою CakePHP для виведення блоку сценаріїв JavaScript з використанням рідного PHP json_encode. $contractorCompaniesмістить значення, які мають одиничні лапки, і як пояснено вище, і, як очікується json_encode($contractorCompanies), не уникає їх, оскільки його дійсний JSON.

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

Додаючи додавання () навколо кодованого рядка JSON, ви уникаєте лапок, що дозволяють Cake / PHP повторювати правильний JavaScript у браузері. Помилки JS зникають.

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

1

Я намагався зберегти об'єкт JSON з запиту XHR в атрибут HTML5 data- *. Я перепробував багато вищезазначених рішень без успіху.

Що я нарешті роблю, це замінити єдину цитату 'на неї кодом &#39;за допомогою регулярного вираження після виклику методу stringify () наступним чином:

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_encode у PHP) або ви вручну будуєте рядок JSON?

Єдине, що захоплює мою увагу, - це апостроф втечі ( \'). Бачачи, як ви використовуєте подвійні лапки, як і справді, не потрібно уникати одинарних лапок. Я не можу перевірити, чи справді це причина вашої помилки jQuery, оскільки я ще не оновлювався до версії 1.4.1.


Я використовую бібліотеку в PHP для створення об'єкта JSON - якось пропустив це записати. Дякуємо, що вказали на це.
Ерік Черпняк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.