2017-10-17 41 views
0

我不得不解析(並最終重新串行)一些狡猾的JSON。它看起來像這樣:如何反序列化狡猾的JSON(帶有不正確引用的字符串和丟失的括號)?

{ 
    name: "xyz", 
    id: "29573f59-85fb-4d06-9905-01a3acb2cdbd", 
    status: "astatus", 
    color: colors["Open"] 
}, 
{ 
    name: "abc", 
    id: "29573f59-85fb-4d06-9905-01a3acb2cdbd", 
    status: "astatus", 
    color: colors["Open"] 
} 

這裏有很多問題 - 從最嚴重的開始。

  1. WTF甚至是什麼?如果我放棄'顏色',那麼我可以得到一串字符串,但我無法調整以開箱即用。

  2. 這是一個沒有方括號的數組。我可以通過將其包裹在其中來解決這個問題。但是有沒有辦法支持開箱即用?

  3. 房產沒有引號。反序列化對這些很不錯..但是反序列化只是沒有骰子。

任何處理這個結構和內部結構的建議嗎?

+1

你不能使用標準的JSON解析器來解析它,因爲它不是有效的JSON。你必須編寫你自己的,或找到一種方法來處理傳入的字符串,然後再將它交給解析器。顯然,最好的解決方案是修復這個狡猾的數據源,但我們是否理解這超出了你的控制範圍?究竟是什麼抽出這個垃圾,並調用JSON?大多數編程語言現在都有內置的JSON序列化工具,所以實際上很難產生無效的輸出。 – ADyson

+0

您一次提出多個問題。首選格式是[每個帖子一個問題](https://meta.stackexchange.com/q/222735/344280)。 – dbc

回答

1

回答你的問題#1 - #3依次是:

  1. Json.NET不支持的形式colors["Open"](其中,因爲你注意到,違反了JSON standard)讀取狡猾的屬性值。

    相反,您需要手動修復這些值,例如,通過某種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)); 
    

    這改變了color屬性值到正確轉義JSON字符串:

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

    Json.NET確實,但是,有能力狡猾的屬性值由從custom JsonConverter內撥打JsonWriter.WriteRawValue()

    定義以下轉換器:在您的JSON

    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; } 
    } 
    

    然後,重新序列化時,你會得到原來狡猾的值:

    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); 
        } 
    } 
    

    然後定義您的RootObject如下。

  2. 支持反向擴展逗號分隔的無外部括號的JSON將在10.0.3之後的Json.NET的下一個版本中發佈。有關詳細信息,請參閱Issue 1396Issue 1355。您需要設置JsonTextReader.SupportMultipleContent = true才能使其工作。

    同時,作爲一種解決方法,你可以通過Rex MChainedTextReaderpublic static TextReader Extensions.Concat(this TextReader first, TextReader second)從答案How to string multiple TextReaders together?並用方括號括[]您的JSON。

    因此,你會反序列化JSON如下:

    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); 
    } 
    

    (或者您也可以手動環繞你的JSON字符串[],但我寧願不涉及抄襲可能大串的解決方案)

    如果使用自己的JsonTextWriterCloseOutput = false分別序列化每個項目,則可以重新序列化無根外括號的根集合。您也可以在每個序列化商品之間手動編寫一個,,並在每個JsonTextWriter共享的基礎TextWriter之間寫入。

  3. 如果您設置了JsonTextWriter.QuoteName = false,則可以序列化不帶周圍引號字符的JSON屬性名稱。

    因此,重新系列化你List<RootObject>沒有引用屬性名稱或外支架,這樣做:

    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(); 
    

樣品.Net fiddle顯示操作這一切。

相關問題