How can I deserialize an invalid json ? Truncated list of objects

前端 未结 3 411
情书的邮戳
情书的邮戳 2020-11-28 16:16

My json file is mostly an array that contain objects but the list is incomplete, so I can\'t use the last entry. I would like to deserialize the rest of the file while disc

相关标签:
3条回答
  • 2020-11-28 16:29

    Looks like on Json.NET 8.0.3 you can stream your string from a JsonTextReader to a JTokenWriter and get a partial result by catching and swallowing the JsonReaderException that gets thrown when parsing the truncated JSON:

    JToken root;
    string exceptionPath = null;
    using (var textReader = new StringReader(badJson))
    using (var jsonReader = new JsonTextReader(textReader))
    using (JTokenWriter jsonWriter = new JTokenWriter())
    {
        try
        {
            jsonWriter.WriteToken(jsonReader);
        }
        catch (JsonReaderException ex)
        {
            exceptionPath = ex.Path;
            Debug.WriteLine(ex);
        }
        root = jsonWriter.Token;
    }
    
    Console.WriteLine(root);
    if (exceptionPath != null)
    {
        Console.WriteLine("Error occurred with token: ");
        var badToken = root.SelectToken(exceptionPath);
        Console.WriteLine(badToken);
    }
    

    This results in:

    [
      {
        "key": "value1"
      },
      {
        "key ": "value2"
      },
      {}
    ]
    

    You could then finish deserializing the partial object with JToken.ToObject. You could also delete the incomplete array entry by using badToken.Remove().

    It would be better practice not to generate invalid JSON in the first place though. I'm also not entirely sure this is documented functionality of Json.NET, and thus it might not work with future versions of Json.NET. (E.g. conceivably Newtonsoft could change their algorithm such that JTokenWriter.Token is only set when writing is successful.)

    0 讨论(0)
  • 2020-11-28 16:43

    You can use the JsonReader class and try to parse as far as you get. Something like the code below will parse as many properties as it gets and then throw an exception. This is of course if you want to deserialize into a concrete class.

    public Partial FromJson(JsonReader reader)
    {
        while (reader.Read())
        {
            // Break on EndObject
            if (reader.TokenType == JsonToken.EndObject)
                break;
    
            // Only look for properties
            if (reader.TokenType != JsonToken.PropertyName)
                continue;
    
            switch ((string) reader.Value)
            {
                case "Id":
                    reader.Read();
                    Id = Convert.ToInt16(reader.Value);
                    break;
    
                case "Name":
                    reader.Read();
                    Name = Convert.ToString(reader.Value);
                    break;
    
            }
        }
    
        return this;
    }
    

    Code taken from the CGbR JSON Target.

    0 讨论(0)
  • 2020-11-28 16:43

    the second answer above is really good and simple, helped me out!

            static string FixPartialJson(string badJson)
            {
                JToken root;
                string exceptionPath = null;
                using (var textReader = new StringReader(badJson))
                using (var jsonReader = new JsonTextReader(textReader))
                using (JTokenWriter jsonWriter = new JTokenWriter())
                {
                    try
                    {
                        jsonWriter.WriteToken(jsonReader);
                    }
                    catch (JsonReaderException ex)
                    {
                        exceptionPath = ex.Path;                    
                    }
                    root = jsonWriter.Token;
                }
    
                return root.ToString();            
            }
    
    0 讨论(0)
提交回复
热议问题