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

时间:2016-08-25 20:15:57

标签: c# json json.net

我从公共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}}"
      }
   ]
}

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

4 个答案:

答案 0 :(得分:1)

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

  1. 您可以使用enter image description here对JSON进行预处理,并将文字 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<RootObject>(); 字符串替换为已解析的等效字符串:

    JsonConverter
  2. 您可以为对应于每个Body对象的POCO引入一个通用LINQ to JSON,该对象将传入的嵌入式JSON字符串文字解析为public class EmbeddedLiteralConverter<T> : 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<T>.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(); } } 层次结构,然后反序列化:< / p>

        var root = JsonConvert.DeserializeObject<RootObject>(json, new EmbeddedLiteralConverter<Body>());
    

    然后使用它:

    "body"

    请注意,转换器会检查传入的JSON令牌是否为字符串,如果不是,则直接反序列化。因此,当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<Respons> responses { get; set; } } JSON是并且不是双序列化时,转换器应该可用。

  3. 出于测试目的,我使用Transport生成了以下目标类:

    {{1}}

答案 1 :(得分:0)

  1. 您可以将其反序列化为具有属性[:alnum:]
  2. 的中间类
  3. 将“body”字符串反序列化为适当的类型
  4. 创建代表目标模型的类的新实例。
  5. 序列化该模型
  6. 这是一个使用动态类型和匿名对象执行此操作的程序。

    string Body {get; set;}

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

答案 2 :(得分:0)

这是我在Sam I am's answer基础上使用的可行解决方案:

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

答案 3 :(得分:0)

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

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