How to deserialize dodgy JSON (with improperly quoted strings, and missing brackets)?

Answering your questions #1 – #3 in order:

  1. Json.NET does not support reading dodgy property values in the form colors["Open"] (which, as you correctly note, violates the JSON standard).

    Instead, you will need to manually fix these values, e.g. through some sort of Regex:

    var regex = new Regex(@"(colors\[)(.*)(\])");
    var fixedJsonString = regex.Replace(jsonString, 
        m => string.Format(@"""{0}{1}{2}""", m.Groups[1].Value, m.Groups[2].Value.Replace("\"", "\\\""), m.Groups[3].Value));
    

    This changes the color property values into properly escaped JSON strings:

    color: "colors[\"Open\"]"
    

    Json.NET does, however, have the capability to write dodgy property values by calling JsonWriter.WriteRawValue() from within a custom JsonConverter.

    Define the following converter:

    public class RawStringConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(string);
        }
    
        public override bool CanRead { get { return false; } }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var s = (string)value;
            writer.WriteRawValue(s);
        }
    }
    

    Then define your RootObject as follows:

    public class RootObject
    {
        public string name { get; set; }
        public string id { get; set; }
        public string status { get; set; }
    
        [JsonConverter(typeof(RawStringConverter))]
        public string color { get; set; }
    }
    

    Then, when re-serialized, you will get the original dodgy values in your JSON.

  2. Support for deserializing comma-delimited JSON without outer brackets will be in the next release of Json.NET after 10.0.3. see Issue 1396 and Issue 1355 for details. You will need to set JsonTextReader.SupportMultipleContent = true to make it work.

    In the meantime, as a workaround, you could grab ChainedTextReader and public static TextReader Extensions.Concat(this TextReader first, TextReader second) from the answer to How to string multiple TextReaders together? by Rex M and surround your JSON with brackets [ and ].

    Thus you would deserialize your JSON as follows:

    List<RootObject> list;
    using (var reader = new StringReader("[").Concat(new StringReader(fixedJsonString)).Concat(new StringReader("]")))
    using (var jsonReader = new JsonTextReader(reader))
    {
        list = JsonSerializer.CreateDefault().Deserialize<List<RootObject>>(jsonReader);
    }
    

    (Or you could just manually surround your JSON string with [ and ], but I prefer solutions that don’t involve copying possibly large strings.)

    Re-serializing a root collection without outer braces is possible if you serialize each item individually using its own JsonTextWriter with CloseOutput = false. You can also manually write a , between each serialized item to the underlying TextWriter shared by every JsonTextWriter.

  3. Serializing JSON property names without a surrounding quote character is possible if you set JsonTextWriter.QuoteName = false.

    Thus, to re-serialize your List<RootObject> without quoted property names or outer braces, do:

    var sb = new StringBuilder();
    bool first = true;
    using (var textWriter = new StringWriter(sb))
    {
        foreach (var item in list)
        {
            if (!first)
            {
                textWriter.WriteLine(",");
            }
            first = false;
            using (var jsonWriter = new JsonTextWriter(textWriter) { QuoteName = false, Formatting = Formatting.Indented, CloseOutput = false })
            {
                JsonSerializer.CreateDefault().Serialize(jsonWriter, item);
            }
        }
    }
    
    var reserializedJson = sb.ToString();
    

Sample .Net fiddle showing all this in action.

Leave a Comment