我必须解析(并最终重新序列化)一些狡猾的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"] }
这里有很多问题-从最严重的问题开始。
color: colors["Open"]
WTF甚至是吗?如果我放弃“颜色”,那么我可以得到一系列的字符串,但是我不能调整以开箱即用。
它是一个没有方括号的数组。我可以将它们包裹起来以解决此问题。但是有没有一种现成的支持方式?
属性没有引号。反序列化对于这些很好,但是重新序列化不是一个骰子。
关于处理此结构的任何建议?
按顺序回答您的问题#1-#3:
colors["Open"]
相反,您将需要手动修复这些值,例如通过某种方式Regex:
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
color: "colors[\"Open\"]"
但是,Json.NET确实具有通过在custom内调用来 编写 狡猾的属性值的功能。JsonWriter.WriteRawValue()JsonConverter
JsonWriter.WriteRawValue()
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如下:
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中获得原始的躲避值。
JsonTextReader.SupportMultipleContent = true
因此,您可以按以下方式反序列化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字符串括起来],但我更喜欢不涉及复制可能很大的字符串的解决方案。)
[
]
重新序列根集合,而不外括号,如果你序列化的每个项目单独利用自身可能JsonTextWriter有CloseOutput = false。您还可以,在每个序列化项目之间手动将a写入每个用户TextWriter共享的基础JsonTextWriter。
JsonTextWriter
CloseOutput = false
,
TextWriter
JsonTextWriter.QuoteName = false
因此,要重新序列化List<RootObject>不带引号的属性名称或大括号,请执行以下操作:
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小提琴展示了所有这些动作。