无法解析由 .NET Serializer 序列化的 JSON 字符串

Posted

技术标签:

【中文标题】无法解析由 .NET Serializer 序列化的 JSON 字符串【英文标题】:Can't parse a JSON string serialized by .NET Serializer 【发布时间】:2018-02-18 05:51:14 【问题描述】:

当我使用 System.Web.Script.Serialization.Serialize() 序列化来自恰好包含引号的 DataTable 中的一些数据时,我得到一个似乎有效的 JSON 字符串。

我用来序列化的VB代码是这样的:

Public Shared Function DataTableToJSONWithjavascriptSerializer(table As DataTable) As String
        Dim jsSerializer As New JavaScriptSerializer()
        Dim parentRow As New List(Of Dictionary(Of String, Object))()
        Dim childRow As Dictionary(Of String, Object)
        For Each row As DataRow In table.Rows
            childRow = New Dictionary(Of String, Object)()
            For Each col As DataColumn In table.Columns
                childRow.Add(col.ColumnName, row(col))
            Next
            parentRow.Add(childRow)
        Next
        Return jsSerializer.Serialize(parentRow)
End Function

Dim str_sql As String = "SELECT TOP 1 create_date, content FROM tbl_dent"
Dim obj_rdr As SqlDataReader
' ...
' some code suppressed for brevity
Dim obj_dt As New DataTable()
obj_dt.Load(obj_rdr)
Dim str_javascript_string As String = "var str = '" _
    & DataTableToJSONWithJavaScriptSerializer(obj_dt).Replace("[","").Replace("]","") & "';"
' append this script to web page

编辑(解决方案,根据@Heinzi 下面的回答):

'instead of this:
Dim str_javascript_string As String = "var str = '" _
    & DataTableToJSONWithJavaScriptSerializer(obj_dt).Replace("[","").Replace("]","") & "';"
'this:
Dim jsSecondSerializer As New JavaScriptSerializer()
Dim str_javascript_string As String = "var str = " _
    & jsSecondSerializer.serialize(DataTableToJSONWithJavaScriptSerializer(obj_dt).Replace("[","").Replace("]","")) & ";"

输出示例(包含引号)如下:

var str = '"create_date":"2017-09-08T22:30:11.674Z","content":"This dent is 4\" wide."';

但是当我尝试解析它时,像这样:

var obj = JSON.parse(str);

我收到此错误:Uncaught SyntaxError: Unexpected token w in JSON at position 69

为什么?我无法想象我需要手动搜索和双转义引号......?我当然可以依靠序列化程序来正确生成可用的 json 字符串吗?

【问题讨论】:

【参考方案1】:

您的字符串转义不正确。你有这个字符串:

"create_date":"2017-09-08T22:30:11.674Z","content":"This dent is 4\" wide."

您显然想将其编码为 JavaScript 字符串文字。在 JavaScript 中,\ 具有特殊含义,即使在单引号括起来的字符串中使用¹,所以您需要对其进行转义:

// JavaScript
var str = '"create_date":"2017-09-08T22:30:11.674Z","content":"This dent is 4\\" wide."';

如果你的字符串中有任何单引号,你也需要转义它们。

当然,您不应该手动执行此操作是对的。所以最简单的解决方案是再次通过 JavaScriptSerializer.Serialize 运行这个字符串:

// C#
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var x = serializer.Serialize(@"""create_date"":""2017-09-08T22:30:11.674Z"",""content"":""This dent is 4\"" wide.""");
Console.WriteLine("var str = " + x + ";");

// yields
// var str = "\"create_date\":\"2017-09-08T22:30:11.674Z\",\"content\":\"This dent is 4\\\" wide.\"";

因此,简而言之,您需要运行 Serialize 两次

一次将您的对象转换为 JSON 字符串,然后 一次将您的 JSON 字符串转换为 JavaScript 字符串文字。

¹ 在 JavaScript 控制台中尝试 '"' === '\"' 并注意它会生成 true

【讨论】:

谢谢。我遵循您的逻辑,但我不清楚如何应用您的答案,因为我的原始问题中可能没有包含足够的上下文。我已经对其进行了编辑以表明有问题的数据来自数据库,并且在没有实际处理单个文本字符串的情况下被序列化,所以我不确定如何将它序列化两次,正如你所建议的那样。这有意义吗?您能否轻松建议如何在这种情况下正确序列化? @Octavient: DataTableToJSONWithJavaScriptSerializer 返回一个字符串。你用那个字符串做什么?请在您的问题中表明这一点。 我已经修改了原始问题,以展示如何使用该函数将字符串传递到网页。 @Octavient:谢谢。请注意,通过创建str_javascript_string,您可以手动在字符串周围添加单引号。你为什么这样做?您这样做是为了将字符串 a 转换为 JavaScript 字符串文字 'a'。但这不是将字符串转换为 JavaScript 字符串文字的好方法:如果字符串包含 ' 或(在您的情况下)反斜杠,它将失败。因此,不要那样做。要么正确转换字符串(通过再次通过序列化运行它而不是添加单引号)或只是删除单引号(如我的其他答案所建议的那样)并将其直接分配给obj 就是这样!谢谢!对于后代,我在上面编辑了我的原始问题,以反映这个已接受的答案。 (不确定这种事情的 SO 协议是什么——我愿意对此提供反馈)【参考方案2】:

我的其他答案如前所述回答了您的问题,但我想为您的潜在问题提出一个替代方案:

因为 JSON 通常 (except when it contains some exotic Unicode whitespace characters) 有效的 JavaScript,为什么要对 JSON 对象进行字符串化和解析?只需去掉单引号并将其直接用作 JavaScript 对象:

// JavaScript
var obj = "create_date":"2017-09-08T22:30:11.674Z","content":"This dent is 4\" wide.";

【讨论】:

我通常会这样做,但这是作为字符串存储在浏览器存储(在兼容浏览器中)中的数据,因为我认为在服务器上进行序列化与字符串化一样简单在客户端,我决定在服务器上序列化。当然,这可能被证明是一个错误的假设。

以上是关于无法解析由 .NET Serializer 序列化的 JSON 字符串的主要内容,如果未能解决你的问题,请参考以下文章

Cf序列化器-Serializer解析

在ASP.NET MVC中全局应用JSON Serializer设置

在 ActiveModel::Serializer 中序列化错误哈希

由于在 Serializer 中评估 QuerySet,迁移无法运行?

用于深层嵌套对象的自定义Json Serializer

DRF Serializer 的many参数是干嘛的