由于JSON中的单引号转义,jQuery.parseJSON抛出“无效的JSON”错误

时间:2010-02-16 18:39:18

标签: javascript jquery json

我正在使用jQuery.post()向我的服务器发出请求,而我的服务器正在返回JSON对象(例如{ "var": "value", ... })。但是,如果任何值包含单引号(正确转义为\'),则jQuery无法解析其他有效的JSON字符串。以下是我的意思(done in Chrome’s console)示例:

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

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

这是正常的吗?有没有办法通过JSON正确传递单个引用?

7 个答案:

答案 0 :(得分:324)

根据JSON website上的状态机图,只允许使用转义双引号字符,而不是单引号。单引号字符不需要转义:

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


更新 - 感兴趣的人的更多信息:


道格拉斯·克罗克福德没有明确说明为什么JSON规范不允许在字符串中使用转义单引号。但是,在Appendix E of JavaScript: The Good Parts中讨论JSON时,他写道:

  

JSON的设计目标是最小化,可移植性,文本性和JavaScript的子集。为了实现互操作,我们需要达成一致意见的越少,我们就越容易互操作。

所以也许他决定只允许使用双引号定义字符串,因为这是所有JSON实现必须达成一致的规则。因此,字符串中的单引号字符不可能意外终止字符串,因为根据定义,字符串只能以双引号字符终止。因此,不需要允许在正式规范中转义单引号字符。

<小时/> 进一步深入研究,Crockford的org.json JSON for 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逻辑基于if 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也没有。

答案 1 :(得分:16)

如果您需要在字符串中使用单引号,因为规范未定义\',请使用\u0027查看http://www.utf8-chartable.de/所有

编辑:请原谅我在评论中滥用反对词这个词。我的意思是反斜杠。我的观点是,如果你在其他字符串中嵌套了字符串,我认为使用unicode而不是大量的反斜杠来逃避单引号会更有用和可读。如果你没有嵌套,那么在那里放一个普通的旧报价确实更容易。

答案 2 :(得分:4)

我理解问题出在哪里,当我查看规范时,明确表示应该正确解析未转义的单引号。

我正在使用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>

如果我使用&#34;&#34;而不是&#39;&#39;它仍然会引发错误。

<强> SOLUTION:

对我来说唯一有用的是使用位掩码JSON_HEX_APOS来转换单引号,如下所示:

json_encode($tmp, JSON_HEX_APOS);

还有另一种方法可以解决这个问题吗?我的代码是错误还是写得不好?

由于

答案 3 :(得分:3)

在查询中发送单引号时

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

当您获得包含单引号的值时

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

如果要在查询中搜索/插入包含单引号的值 xxx=Replace(empid,"'","''")

答案 4 :(得分:2)

使用CakePHP使用PHP的本地json_encode输出JavaScript脚本块来解决类似的问题。 $contractorCompanies包含具有单引号的值,如上所述,预期json_encode($contractorCompanies)因其有效的JSON而无法转义它们。

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

通过在JSON编码的字符串周围添加addslashes(),然后转义引号,允许Cake / PHP将正确的javascript回显到浏览器。 JS错误消失了。

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

答案 5 :(得分:0)

有趣。你是如何在服务器端生成JSON的?您使用的是库函数(例如PHP中的json_encode),还是手工构建JSON字符串?

唯一引起我注意的是逃避撇号(\')。看到你正在使用双引号,正如你确实应该的那样,没有必要逃避单引号。我无法检查这是否确实是导致jQuery错误的原因,因为我还没有更新到1.4.1版本。

答案 6 :(得分:0)

我试图将XSON对象从XHR请求保存到HTML5 data- *属性中。我尝试了上述许多解决方案但没有成功。

我最终要做的是在stringify()方法调用以下方式之后使用正则表达式用代码'替换单引号&#39;

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.