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

前端 未结 1 846
刺人心
刺人心 2020-12-04 03:45

I am having to parse (and ultimately reserialize) some dodgy JSON. it looks like this:

{
  name: \"xyz\",
  id: \"29573f59-85fb-4d06-9905-01a3acb2cdbd\",
  s         


        
相关标签:
1条回答
  • 2020-12-04 04:26

    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.

    0 讨论(0)
提交回复
热议问题