如何反序列化不可靠的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. color: colors["Open"]

    甚至是WTF?如果我去掉"colors",那么我可以得到一组字符串,但我无法调整以开箱即用。

  2. 它是一个没有方括号的数组。我可以把它们包起来。但是,有没有一种方法可以开箱即用地提供支持?

  3. 属性没有引号。反序列化对这些来说很好。。但保留不是骰子。

有任何关于处理此结构内外的建议吗?

按顺序回答您的问题#1-#3:

  1. Json.NET不支持读取colors["Open"]形式的不可靠属性值(正如您正确指出的,这违反了Json标准)。

    相反,您需要手动修复这些值,例如通过某种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确实能够通过从自定义JsonConverter中调用JsonWriter.WriteRawValue()写入不可靠的属性值。

    定义以下转换器:

    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如下:

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

    然后,当重新序列化时,您将在JSON中获得原始的不可靠值。

  2. 在10.0.3之后的JSON.NET的下一个版本中,将支持反序列化不带外括号的逗号分隔的JSON。有关详细信息,请参见第1396期和第1355期。您需要设置JsonTextReader.SupportMultipleContent = true才能使其工作。

    同时,作为一种变通方法,您可以从Rex M对How to string multiple TextReaders together?的回答中获取ChainedTextReaderpublic static TextReader Extensions.Concat(this TextReader first, TextReader second),并用括号[]包围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();
    

Sample.Net fiddle显示了所有这些。

相关内容

  • 没有找到相关文章

最新更新