如何反序列化狡猾的JSON(带有不正确引用的字符串和丢失的括号)?
我不得不解析(并最终重新串行)一些狡猾的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"]
}
这里有很多问题 - 从最严重的开始。
-
WTF甚至是什么?如果我放弃'颜色',那么我可以得到一串字符串,但我无法调整以开箱即用。
这是一个没有方括号的数组。我可以通过将其包裹在其中来解决这个问题。但是有没有办法支持开箱即用?
房产没有引号。反序列化对这些很不错..但是反序列化只是没有骰子。
任何处理这个结构和内部结构的建议吗?
回答你的问题#1 - #3依次是:
-
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
如下。 -
支持反向扩展逗号分隔的无外部括号的JSON将在10.0.3之后的Json.NET的下一个版本中发布。有关详细信息,请参阅Issue 1396和Issue 1355。您需要设置
JsonTextReader.SupportMultipleContent = true
才能使其工作。同时,作为一种解决方法,你可以通过Rex M抢
ChainedTextReader
和public 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字符串
[
和]
,但我宁愿不涉及抄袭可能大串的解决方案)如果使用自己的
JsonTextWriter
和CloseOutput = false
分别序列化每个项目,则可以重新序列化无根外括号的根集合。您也可以在每个序列化商品之间手动编写一个,
,并在每个JsonTextWriter
共享的基础TextWriter
之间写入。 -
如果您设置了
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显示操作这一切。
你不能使用标准的JSON解析器来解析它,因为它不是有效的JSON。你必须编写你自己的,或找到一种方法来处理传入的字符串,然后再将它交给解析器。显然,最好的解决方案是修复这个狡猾的数据源,但我们是否理解这超出了你的控制范围?究竟是什么抽出这个垃圾,并调用JSON?大多数编程语言现在都有内置的JSON序列化工具,所以实际上很难产生无效的输出。 – ADyson
您一次提出多个问题。首选格式是[每个帖子一个问题](https://meta.stackexchange.com/q/222735/344280)。 – dbc