JSON.Net - DeserializeObject格式化

3

我正在使用JSON.Net尝试从SurveyGizmo中反序列化一些调查响应。以下是我读取的数据快照:

{"result_ok":true,
"total_count":"44",
"page":1,
"total_pages":1,
"results_per_page":50,
"data":[
        {"id":"1",
        "contact_id":"",
        "status":"Complete",
        "is_test_data":"0",
        "datesubmitted":"2011-11-13 22:26:53",
        "[question(59)]":"11\/12\/2011",
        "[question(60)]":"06:15 pm",
        "[question(62)]":"72",
        "[question(63)]":"One",
        "[question(69), option(10196)]":"10",

我已经设置了一个类来处理日期提交,但是我不确定如何设置类来反序列化问题,因为问题的数量将会发生变化?如果存在选项,我还需要捕获选项。

我正在使用以下代码来使用JSON.NET Deserialize函数:

Dim responses As Responses = JsonConvert.DeserializeObject(Of Responses)(fcontents)

类:

Public Class Responses
    Public Property result_OK As Boolean

    Public Property total_count As Integer

    Public Property page As Integer

    Public Property total_pages As Integer

    Public Property results_per_page As Integer

    Public Overridable Property data As List(Of surveyresponse)
End Class

Public Class SurveyResponse
    Public Property id As Integer

    Public Property status As String

    Public Property datesubmitted As Date
End Class
1个回答

2

支持非常疯狂的映射的技巧是使用JsonConverter并完全替换该对象的解析(对于C#我很抱歉,但我不擅长VB语法):

class Program
{
    static void Main(string[] args)
    {
        var result = JsonConvert.DeserializeObject<Responses>(TestData);
    }

    const string TestData = @"{""result_ok"":true,
""total_count"":""44"",
""page"":1,
""total_pages"":1,
""results_per_page"":50,
""data"":[
    {""id"":""1"",
    ""contact_id"":"""",
    ""status"":""Complete"",
    ""is_test_data"":""0"",
    ""datesubmitted"":""2011-11-13 22:26:53"",
    ""[question(59)]"":""11\/12\/2011"",
    ""[question(60)]"":""06:15 pm"",
    ""[question(62)]"":""72"",
    ""[question(63)]"":""One"",
    ""[question(69), option(10196)]"":""10"",
}]}";
}

[JsonObject]
class Responses
{
    public bool result_ok { get; set; }
    public string total_count { get; set; }
    public int page { get; set; }
    public int total_pages { get; set; }
    public int results_per_page { get; set; }
    public SurveyResponse[] Data { get; set; }
}

[JsonObject]
// Here is the magic: When you see this type, use this class to read it.
// If you want, you can also define the JsonConverter by adding it to
// a JsonSerializer, and parsing with that.
[JsonConverter(typeof(DataItemConverter))]
class SurveyResponse
{
    public string id { get; set; }
    public string contact_id { get; set; }
    public string status { get; set; }
    public string is_test_data { get; set; }
    public DateTime datesubmitted { get; set; }
    public Dictionary<int, string> questions { get; set; }
}

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

    public override bool CanRead
    {
        get { return true; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var value = (SurveyResponse)existingValue;
        if (value == null)
        {
            value = new SurveyResponse();
            value.questions = new Dictionary<int, string>()
        }

        // Skip opening {
        reader.Read();

        while (reader.TokenType == JsonToken.PropertyName)
        {
            var name = reader.Value.ToString();
            reader.Read();

                // Here is where you do your magic
            if (name.StartsWith("[question("))
            {
                int index = int.Parse(name.Substring(10, name.IndexOf(')') - 10));
                value.questions[index] = serializer.Deserialize<string>(reader);
            }
            else
            {
                var property = typeof(SurveyResponse).GetProperty(name);
                property.SetValue(value, serializer.Deserialize(reader, property.PropertyType), null);
            }

            // Skip the , or } if we are at the end
            reader.Read();
        }

        return value;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

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

显然,如果你想使它更加健壮,还有很多工作需要做,但这里给出了基本的操作方式。如果你只需要更改属性名称,那么有更轻量级的替代方案(要么使用JsonPropertyAttribute,要么重写DefaultContractResolver.ResolvePropertyName()),但这将为您提供完全的控制权。


Simon, 我很感激你在回复中所付出的努力! 起初,我有点被回复吓到了,我希望它会简单明了!到目前为止,它已经运行得不错,除了那些带有选项的问题,例如:"[question(31), option(10019)]":"39.99",值得注意的是,question(31)可能会有多个选项响应。 因此,我认为我需要开始捕获question_id、option_id和value,但我不认为我可以用字典来实现这一点? - Tom
我想我已经解决了。我很快会发布我的更改。 - Tom
是的,这只是让您知道如何覆盖属性名称->对象更新过程,我不想猜测option()的含义 :) - Simon Buchan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接