如何处理Json.Net解析中的错误

时间:2014-02-03 02:09:59

标签: c# json parsing json.net

我正在使用Json.Net进行Json反序列化。有时我读的Json字符串是不正确的(我不能修复,因为我不生成它)。特别是,在一个特定的地方,应该有一个字符串,有时会有一个序列化的对象。然后,Json.Net抱怨并不奇怪地找到一个预期字符串的对象。

我发现我可以在Error中使用JsonSerializerSettings拦截此问题,并通过设置ErrorContext.Handled使Json.Net忽略此问题。但我想做更多。如果我可以查看序列化对象,我可以弄清楚字符串应该是什么,并在理论上提供正确的答案。在实践中,我无法想象我们如何做到这一点。特别是在错误处理程序中:

  • 如何访问解析器绊倒的字符串(请注意,如果设置了ErrorContext.Handled,解析器可以成功继续,因此它可以正确地确定问题字符串的开始和结束)?
  • 如何将正确的字符串提供给解析器,或者可以访问当前解析的对象,以便我可以手动设置该值?

[编辑] 根据要求提供了一个简化的例子:

我要解析的错误的Json字符串:

{
    "id": 2623,
    "name": {
        "a": 39,
        "b": 0.49053320637463277,
        "c": "cai5z+A=",
        "name": "22"
    },
    "children": [
        {
            "id": 3742,
            "name": {
                "a": 37,
                "b": 0.19319664789046936,
                "c": "Me/KKPY=",
                "name": "50"
            },
            "children": [
                {
                    "id": 1551,
                    "name": {
                        "a": 47,
                        "b": 0.6935373953047849,
                        "c": "qkGkMwY=",
                        "name": "9"
                    },
                    "children": []
                },
                {
                    "id": 4087,
                    "name": {
                        "a": 5,
                        "b": 0.42905938319352427,
                        "c": "VQ+yH6o=",
                        "name": "84"
                    },
                    "children": []
                },
                {
                    "id": 614,
                    "name": {
                        "a": 19,
                        "b": 0.7610801005554758,
                        "c": "czjTK1s=",
                        "name": "11"
                    },
                    "children": []
                }
            ]
        },
        {
            "id": 3382,
            "name": {
                "a": 9,
                "b": 0.36416331043660793,
                "c": "lnoHrd0=",
                "name": "59"
            },
            "children": [
                {
                    "id": 4354,
                    "name": {
                        "a": 17,
                        "b": 0.8741648112769075,
                        "c": "CD2i2I0=",
                        "name": "24"
                    },
                    "children": []
                },
                {
                    "id": 2533,
                    "name": {
                        "a": 52,
                        "b": 0.8839575992356788,
                        "c": "BxFEzVI=",
                        "name": "60"
                    },
                    "children": []
                },
                {
                    "id": 5733,
                    "name": {
                        "a": 4,
                        "b": 0.7230552787534219,
                        "c": "Un7lJGM=",
                        "name": "30"
                    },
                    "children": []
                }
            ]
        },
        {
            "id": 9614,
            "name": {
                "a": 81,
                "b": 0.4015882813379114,
                "c": "dKgyRZk=",
                "name": "63"
            },
            "children": [
                {
                    "id": 7831,
                    "name": {
                        "a": 81,
                        "b": 0.2784254314743101,
                        "c": "xZur64o=",
                        "name": "94"
                    },
                    "children": []
                },
                {
                    "id": 6293,
                    "name": {
                        "a": 73,
                        "b": 0.32629523068959604,
                        "c": "lMkosP4=",
                        "name": "93"
                    },
                    "children": []
                },
                {
                    "id": 5253,
                    "name": {
                        "a": 13,
                        "b": 0.19240453242901923,
                        "c": "oOPZ3tA=",
                        "name": "5"
                    },
                    "children": []
                }
            ]
        }
    ]
}

然后在课堂上解析它:

class Node
{
     [JsonProperty]
    int id;
     [JsonProperty]
    string name;
     [JsonProperty]
    List<Node> children;
}

正如您所看到的,它需要一个字符串name,但有时会错误地获取一个序列化对象(其中包含有问题的字符串作为成员)。这只发生在一些JSON字符串中,而不发生在其他字符串中,所以我不能只改变Node的类定义来匹配。

[编辑2] 根据我的API,“正确”的Json字符串将如下所示:

{
    "id": 2623,
    "name": "22",
    "children": [
        {
            "id": 3742,
            "name": "50",
            "children": [
                {
                    "id": 1551,
                    "name": "9",
                    "children": []
                },
                {
                    "id": 4087,
                    "name":"84",
                    "children": []
                },
                ...

1 个答案:

答案 0 :(得分:2)

如您所见,尝试在事后检测错误,然后从错误点重新分析将会出现问题。幸运的是,您所描述的问题可以使用自定义JsonConverter以简单的方式解决。我们的想法是让转换器将数据读入一个临时结构,该结构可以处理表单(对象或字符串),查询类型,然后从那里构造Node

以下是转换器的代码:

class NodeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Node));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);

        Node node = new Node();
        node.id = (int)jo["id"];

        JToken name = jo["name"];
        if (name.Type == JTokenType.String)
        {
            // The name is a string at the current level
            node.name = (string)name;
        }
        else
        {
            // The name is one level down inside an object
            node.name = (string)name["name"];
        }

        node.children = jo["children"].ToObject<List<Node>>(serializer);

        return node;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

要使用转换器,请在[JsonConverter]类中添加Node属性,如下所示:

[JsonConverter(typeof(NodeConverter))]
class Node
{
    public int id { get; set; }
    public string name { get; set; }
    public List<Node> children { get; set; }
}

然后你可以正常反序列化:

Node node = JsonConvert.DeserializeObject<Node>(json);

这是一个完整的演示,展示了转换器的运行情况。为了便于说明,我创建了一个新的JSON字符串,其中包含您在问题中描述的“好”和“坏”节点的组合。

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""id"": 2623,
            ""name"": {
                ""a"": 39,
                ""b"": 0.49053320637463277,
                ""c"": ""cai5z+A="",
                ""name"": ""22""
            },
            ""children"": [
                {
                    ""id"": 3741,
                    ""name"": ""50"",
                    ""children"": [
                        {
                            ""id"": 1550,
                            ""name"": ""9"",
                            ""children"": []
                        },
                        {
                            ""id"": 4088,
                            ""name"": {
                                ""a"": 5,
                                ""b"": 0.42905938319352427,
                                ""c"": ""VQ+yH6o="",
                                ""name"": ""85""
                            },
                            ""children"": []
                        }
                    ]
                },
                {
                    ""id"": 3742,
                    ""name"": {
                        ""a"": 37,
                        ""b"": 0.19319664789046936,
                        ""c"": ""Me/KKPY="",
                        ""name"": ""51""
                    },
                    ""children"": [
                        {
                            ""id"": 1551,
                            ""name"": {
                                ""a"": 47,
                                ""b"": 0.6935373953047849,
                                ""c"": ""qkGkMwY="",
                                ""name"": ""10""
                            },
                            ""children"": []
                        },
                        {
                            ""id"": 4087,
                            ""name"": ""84"",
                            ""children"": []
                        }
                    ]
                }
            ]
        }";

        Node node = JsonConvert.DeserializeObject<Node>(json);
        DumpNode(node, "");
    }

    private static void DumpNode(Node node, string indent)
    {
        Console.WriteLine(indent + "id = " + node.id + ", name = " + node.name);
        foreach(Node child in node.children)
        {
            DumpNode(child, indent + "    ");
        }
    }
}

输出:

id = 2623, name = 22
    id = 3741, name = 50
        id = 1550, name = 9
        id = 4088, name = 85
    id = 3742, name = 51
        id = 1551, name = 10
        id = 4087, name = 84