如何反序列化狡猾的JSON(带有不正确的引用字符串和缺少括号)?

时间:2017-10-17 11:13:02

标签: arrays json json.net

我不得不解析(并最终重新编译)一些狡猾的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即便如此?如果我删除“颜色”,那么我可以获得一系列字符串,但我不能调整开箱即用。

  2. 这是一个没有方括号的数组。我可以通过包装它来解决这个问题。但有没有办法支持开箱即用?

  3. 属性没有引号。反序列化对于这些来说是好的..但是重新排序只是没有骰子。

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

1 个答案:

答案 0 :(得分: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可以通过在JsonWriter.WriteRawValue()内调用custom JsonConverter编写狡猾的属性值。

    定义以下转换器:

    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. 支持对没有外括号的逗号分隔的JSON进行反序列化将在10.0.3之后的Json.NET的下一个版本中。有关详细信息,请参阅Issue 1396Issue 1355。您需要设置JsonTextReader.SupportMultipleContent = true才能使其正常工作。

    与此同时,作为一种解决方法,您可以通过How to string multiple TextReaders together?Rex M的答案中抓取ChainedTextReaderpublic static TextReader Extensions.Concat(this TextReader first, TextReader second),并用括号{{1}围绕您的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字符串,但我更喜欢不涉及复制大字符串的解决方案。)

    如果使用自己的]CloseOutput = false单独序列化每个项目,则可以重新序列化没有外括号的根集合。您还可以手动将每个序列化项目之间的JsonTextWriter写入每个,共享的基础TextWriter

  3. 如果设置JsonTextWriter.QuoteName = false,则可以序列化没有周围引号字符的JSON属性名称。

    因此,要重新序列化JsonTextWriter而不引用属性名称或外括号,请执行以下操作:

    List<RootObject>
  4. 示例.Net fiddle显示所有这些内容。