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/ для всех из них

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


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))."' );"); ?>

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.

0

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

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


Я использую библиотеку в PHP для генерации объекта JSON - вроде пропустил, чтобы записать это. Спасибо что подметил это.
— Эрик Черпняк
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.