如何在JSON对象中转换转义的JSON字符串?

我从公共API接收一个JSON对象,其属性本身是一个转义的JSON字符串。

{ "responses":[ { "info":"keep \"this\" in a string", "body":"{\"error\":{\"message\":\"Invalid command\",\"type\":\"Exception\",\"code\":123}}" }, { "info":"more \"data\" to keep in a string", "body":"{\"error\":{\"message\":\"Other error\",\"type\":\"Exception\",\"code\":321}}" } ] } 

我如何将此属性转换为实际的JSON对象(未转义),以便使用NewtonSoft Json.NET反序列化整个响应?

您的JSON包含实际嵌入的"body"对象的文字字符串,双序列化JSON。 要将其反序列化为POCO层次结构而不需要在任何类型中引入中间string Json surrogate属性,您有以下几个选项:

  1. 您可以使用LINQ to JSON预处理JSON ,并将文本"body"字符串替换为其解析的等效字符串:

      var rootToken = JToken.Parse(json); foreach (var token in rootToken.SelectTokens("responses[*].body").ToList().Where(t => t.Type == JTokenType.String)) { token.Replace(JToken.Parse((string)token)); } var root = rootToken.ToObject(); 
  2. 您可以为与每个Body对象相对应的POCO引入一个通用的JsonConverter ,它将传入的嵌入式JSON字符串文字解析为LINQ to JSON层次结构,然后反序列化:

     public class EmbeddedLiteralConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(T).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; var contract = serializer.ContractResolver.ResolveContract(objectType); if (contract is JsonPrimitiveContract) throw new JsonSerializationException("Invalid type: " + objectType); if (existingValue == null) existingValue = contract.DefaultCreator(); if (reader.TokenType == JsonToken.String) { var json = (string)JToken.Load(reader); using (var subReader = new JsonTextReader(new StringReader(json))) { // By populating a pre-allocated instance we avoid an infinite recursion in EmbeddedLiteralConverter.ReadJson() // Re-use the existing serializer to preserve settings. serializer.Populate(subReader, existingValue); } } else { serializer.Populate(reader, existingValue); } return existingValue; } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } 

    然后使用它像:

      var root = JsonConvert.DeserializeObject(json, new EmbeddedLiteralConverter()); 

    请注意,转换器会检查传入的JSON令牌是否为字符串,如果不是,则直接进行反序列化。 因此,当"body" JSON是并且不是双序列化时,转换器应该是可用的。

出于测试目的,我使用http://json2csharp.com/生成了以下目标类:

 public class Error { public string message { get; set; } public string type { get; set; } public int code { get; set; } } public class Body { public Error error { get; set; } } public class Respons { public string info { get; set; } public Body body { get; set; } } public class RootObject { public List responses { get; set; } } 
  1. 你可以将它反序列化为一个具有属性的中间类: string Body {get; set;} string Body {get; set;}
  2. 将“body”字符串反序列化为适当的类型
  3. 创建表示目标模型的类的新实例。
  4. 序列化该模型

这是一个用动态类型和匿名对象来完成它的程序。

 static void Main(string[] args) { var json = File.ReadAllText("JsonFile1.json"); dynamic obj = JsonConvert.DeserializeObject(json); var dest = new { responses = ((IEnumerable)obj.responses).Select(x => new { info = x.info, body = JsonConvert.DeserializeObject((string)x.body) }) }; var destJson = JsonConvert.SerializeObject(dest); File.WriteAllText("JsonFile2.json", destJson); } 

或者,您可以构建一个新版本的目标类型而不是匿名类型,如果您不想重新编写josn。

这是我根据Sam使用的可行解决方案我的答案 :

 dynamic obj = JsonConvert.DeserializeObject(json); foreach (var response in (IEnumerable)obj.responses) { response.body = JsonConvert.DeserializeObject((string)response.body); } string result = JsonConvert.SerializeObject(obj); 

要将编码为json字符串的json转换为Jobject,您始终可以使用以下技术,

 var token = JToken.Parse(text); var json = JObject.Parse((string) token);