Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I deserialize a JSON text until error or end with Newtonsoft parser? [duplicate]

Tags:

json

json.net

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 discarding the last invalid entry

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

Please tell me if there is a way using Newtonsoft.Json library, or do I need some preprocessing.

Thank you!

like image 380
iteal Avatar asked Apr 12 '16 14:04

iteal


People also ask

How do I deserialize text JSON?

A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.

Which is better Newtonsoft JSON or System text JSON?

Json does case-insensitive property name matching by default. The System. Text. Json default is case-sensitive, which gives better performance since it's doing an exact match.

Is System text JSON faster than Newtonsoft JSON?

So, they created new data types ( Span , etc.) to work more efficiently with Strings to boost JSON performance. In their initial introduction of System. Text. Json, they claimed a 1.5x-5x speedup compared to Newtonsoft Json.Net.

What is the difference between serialize and deserialize JSON?

JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object).


3 Answers

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.)

like image 173
dbc Avatar answered Oct 09 '22 19:10

dbc


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.

like image 41
Toxantron Avatar answered Oct 09 '22 17:10

Toxantron


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();            
        }
like image 23
John Feng Avatar answered Oct 09 '22 19:10

John Feng