jQuery.parseJSON выдает ошибку «Invalid 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
UPDATE :: JQuery очень ограничивает вставку JSON. Если вы попробуете alert ($. ParseJSON ("[\" Ciao \\ '\ "]")); это не работает из-за того, что сообщил Джастин
daitangio
2
« Реализация JSON для Java в Crockford's org.json более допустима и допускает символы одинарных кавычек » # Это просто хорошая практика: принцип надежности
Дункан Джонс
1
@DuncanJones - эта статья может дать представление о том, почему ни один из браузеров, по-видимому, не следует этому принципу в отношении JSON: joelonsoftware.com/items/2008/03/17.html
Джастин Этье,
1
@JustinEthier, как указано в этом ответе stackoverflow.com/a/25491642/759452 , в спецификации JSON tools.ietf.org/html/rfc7159 говорится Any character may be escaped, что это может объяснить, почему в некоторых реализациях допускается экранирование одинарных кавычек.
Адриен Бе
1
@AdrienBe - Интересно ... но они означали, что любой символ может быть экранирован, если он состоит из 4 шестнадцатеричных цифр? В соответствии с приведенной выше диаграммой состояний и диаграммой в разделе 7 RFC экранирование одинарной кавычки в том виде, в котором оно написано, \'по-прежнему не допускается. Было бы хорошо, если бы RFC был более точным в этом вопросе.
Джастин Этье
15

Если вам нужна одиночная кавычка внутри строки, так как \ 'не определена спецификацией, используйте \u0027 см. Http://www.utf8-chartable.de/ для всех из них

редактировать: пожалуйста, извините за неправильное использование обратных слов в комментариях. Я имел в виду обратную косую черту. Я хочу сказать, что в случае, если у вас есть вложенные строки внутри других строк, я думаю, что может быть более полезным и читабельным использовать юникод вместо множества обратных косых черт, чтобы избежать одиночной кавычки. Однако, если вы не вложены, проще поместить туда просто старую цитату.

SLF
источник
29
Просто используйте простую одинарную кавычку.
Джефф Кауфман
Иногда проще использовать юникод, чем тонны обратных тиков. Особенно когда внутри чередуются бэк-тики.
SLF
3
Зачем вам нужны кавычки? Если у вас есть строка типа "foo 'bar'", то вы просто оставляете одинарные кавычки без экранирования.
Джефф Кауфман
3
именно то, что я искал. Я пытаюсь записать строку json на страницу в виде строки js var и заключить ее в одинарные кавычки, и она заканчивалась рано, когда в значении свойства была одинарная кавычка. Теперь я просто делаю json.Replace ("'", "\ u0027") в коде, прежде чем записать его на страницу.
Зак
@ Zack Не следует заключать JSON в кавычки. Если вам нужна строка из существующей строки JSON, просто зафиксируйте ее снова. в PHP, который был бы var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>где myEncodedJsonрезультат предыдущего , json_encodeчто будет заботиться о побеге вашей апостроф, на самом деле, это будет просто выходные что - то большая строка , завернутые в двойных кавычках, так одинарные кавычки не будут экранированы, но двойные кавычки воля.
Хуан Мендес
5

Я понимаю, в чем проблема, и когда я смотрю на спецификации, становится ясно, что одиночные кавычки без экранирования должны быть правильно проанализированы.

Я использую функцию jQuery.parseJSON jquery для разбора строки 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 ("\" <? = $ marker;?> \ ""); В соответствии со спецификацией, строки json должны использовать двойные кавычки, но 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)."' );"); ?>

Добавляя addlashes () вокруг строки, закодированной в JSON, вы избегаете кавычек, позволяющих Cake / PHP выводить правильный код JavaScript в браузер. Ошибки JS исчезают.

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".addslashes(json_encode($contractorCompanies))."' );"); ?>
chopstik
источник
1

Я пытался сохранить объект JSON из XHR-запроса в атрибут data5 * HTML5. Я попробовал многие из вышеперечисленных решений безуспешно.

В конечном итоге я заменил одинарную кавычку 'на код &#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.
BoCyrill
источник
0

Интересный. Как вы генерируете свой JSON на стороне сервера? Используете ли вы библиотечную функцию (например, json_encodeв PHP), или вы строите строку JSON вручную?

Единственное, что привлекает мое внимание - это апостроф ( \'). Поскольку вы используете двойные кавычки, как вы и должны делать, вам не нужно избегать одинарных кавычек. Я не могу проверить, действительно ли это является причиной вашей ошибки jQuery, так как я еще не обновился до версии 1.4.1.

Aistina
источник
Я использую библиотеку в PHP для генерации объекта JSON - вроде пропустил, чтобы записать это. Спасибо что подметил это.
Эрик Черпняк