我应该如何解析JSON,它的键和值的重音被转义而不影响字段值中的转义?

时间:2014-05-20 00:44:19

标签: c# json json.net

使用155-questions-active查询Stack Overflow websockets我得到以下内容(格式不正确)JSON:

{
    "action":"155-questions-active",
    "data":
        "{
            \"siteBaseHostAddress\":\"stackoverflow.com\",
            \"id\":23747905,
            \"titleEncodedFancy\":\"Load sqlite extension in Django\",
            \"bodySummary\":\"I have built a sqlite <snip>\",
            \"tags\":[\"django\",\"sqlite\",\"pysqlite\"],
            \"lastActivityDate\":1400544795,
            \"url\":\"http://stackoverflow.com/questions/23747905/<snip>\",
            \"ownerUrl\":\"http://stackoverflow.com/users/1311165/pro-chats\",
            \"ownerDisplayName\":\"Pro Chats\",
            \"apiSiteParameter\":\"stackoverflow\"
        }"
}

应用一些修正后

    private string MakeJsonCapable(string input)
    {
        input = input.Trim();
        input = input.Replace("data\":\"", "data\":");
        input = input.Remove(input.LastIndexOf("\""), 1);
        input = input.Replace("\\", string.Empty);

        return input;
    }

我得到了这个结果:

{
  "action": "155-questions-active",
  "data": {
    "siteBaseHostAddress": "stackoverflow.com",
    "id": 23747905,
    "titleEncodedFancy": "Load sqlite extension in Django",
    "bodySummary": "I have built a sqlite <snip>",
    "tags": [
      "django",
      "sqlite",
      "pysqlite"
    ],
    "lastActivityDate": 1400544795,
    "url": "http:\/\/stackoverflow.com\/questions\/23747905\/<snip>",
    "ownerUrl": "http:\/\/stackoverflow.com\/users\/1311165\/pro-chats",
    "ownerDisplayName": "Pro Chats",
    "apiSiteParameter": "stackoverflow"
  }
}

现在可接受的JSON(我正在使用some online JSON format tool验证这一点)由JSON.NET完美解析。

当一个值(到目前为止我只在bodySummary中看到但我怀疑titleEncodedFancy也可能有这个)包含"时,会出现问题。在使其成为Json-able之前传递的字面值是\\\"Compliant Solution\\\":3个反斜杠和一个重音。

请注意,这是文字值,并且不包含调试器的任何反斜杠:这是直接从textview获取的; watch变量显示7个反斜杠。

显然这是一个问题,因为现在我的bodySummary包含一个未转义的",它会破坏反序列化。出于这个原因,我无法创建自定义JsonConverter来自己逃避它们,因为它不会在第一时间获得正确的值。

如何删除出现在重音符号前面的不需要的反斜杠,表示字段名称及其值的开头和结尾?

或者:也许我首先错误地解析data字段。如果是这样的话:正确的方法是什么?

2 个答案:

答案 0 :(得分:2)

这里有的是已经序列化为字符串,放在另一个对象中然后第二次序列化的数据。要正确地恢复所有内容,您可以撤消该过程。定义两个类,一个用于外部序列化,另一个用于内部:

class Outer
{
    public string Action { get; set; }
    public string Data { get; set; }
}

class Inner
{
    public string SiteBaseHostAddress { get; set; }
    public int Id { get; set; }
    public string TitleEncodedFancy { get; set; }
    public string BodySummary { get; set; }
    public string[] Tags { get; set; }
    public int LastActivityDate { get; set; }
    public string Url { get; set; }
    public string OwnerUrl { get; set; }
    public string OwnerDisplayName { get; set; }
    public string ApiSiteParameter { get; set; }
}

然后像这样反序列化:

Outer outer = JsonConvert.DeserializeObject<Outer>(json);
Inner inner = JsonConvert.DeserializeObject<Inner>(outer.Data);

执行此操作时,请勿对输入字符串应用“修复”。让JSON解析器完成它的工作。

修改

如果要保持父子关系,则需要自定义JsonConverter来处理子对象的反序列化。为此,首先需要将外部类的定义更改为:

class Outer
{
    public string Action { get; set; }
    [JsonConverter(typeof(InnerConverter))]
    public Inner Data { get; set; }
}

像这样创建InnerConverter类:

class InnerConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Inner));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        return JsonConvert.DeserializeObject<Inner>(token.ToString());
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

最后,您可以像这样反序列化:

Outer outer = JsonConvert.DeserializeObject<Outer>(json);

答案 1 :(得分:1)

按照Brian Rogers的建议,我创建了一个简单的转换器来处理它:

响应

public sealed class Response
{
    [JsonProperty("action")]
    public string Action { get; internal set; }

    [JsonProperty("data")]
    [JsonConverter(typeof (DataConverter))]
    public Data Data { get; internal set; }
}

数据

public sealed class Data
{
    [JsonProperty("siteBaseHostAddress")]
    public string SiteBaseHostAddress { get; internal set; }

    [JsonProperty("id")]
    public string Id { get; internal set; }

    [JsonProperty("titleEncodedFancy")]
    public string TitleEncodedFancy { get; internal set; }

    [JsonProperty("bodySummary")]
    public string BodySummary { get; internal set; }

    [JsonProperty("tags")]
    public IEnumerable<string> Tags { get; internal set; }

    [JsonProperty("lastActivityDate")]
    [JsonConverter(typeof (EpochTimeConverter))]
    public DateTime LastActivityDate { get; internal set; }

    [JsonProperty("url")]
    [JsonConverter(typeof (UriConverter))]
    public Uri QuestionUrl { get; internal set; }

    [JsonProperty("ownerUrl")]
    [JsonConverter(typeof (UriConverter))]
    public Uri OwnerUrl { get; internal set; }

    [JsonProperty("ownerDisplayName")]
    public string OwnerDisplayName { get; internal set; }

    [JsonProperty("apiSiteParameter")]
    public string ApiSiteParameter { get; internal set; }
}

DataConverter

internal sealed class DataConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof (string);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        var value = reader.Value as string;
        return JsonConvert.DeserializeObject<Data>(value);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

现在我可以用

完全反序列化它
var responseObject = JsonConvert.DeserializeObject<Response>(result);