【问题标题】:Parsing Complicated JSON object in windows phone 8 (Dictionary Key/Value pairs)在 windows phone 8 中解析复杂的 JSON 对象(字典键/值对)
【发布时间】:2013-07-24 11:28:38
【问题描述】:

我是 windows phone 8 开发的新手...如何在 windows phone 8 中解析以下数据:

   [
   {
      "detail":{
         "single_selection":[
            {
               "Questions":"If  -2<1\/2x< 4 ,  then",
               "Question Type":"text",
               "Url":"NO URL",
               "options":{
                  "2379":"4 > x < -8",
                  "2380":"4 < x > -8",
                  "2381":"4 < x < -8",
                  "2382":"4 > x > -8"
               },
               "correct Ans":[
                  "2382"
               ],
               "marks":"1",
               "description":"4 > x > -8"
            }
         ]
      }
   }
]

我正在尝试通过以下方式解析:

 namespace TestSample
{
    public partial class MainPage : PhoneApplicationPage
    {
        private const string Con_String = @"isostore:/DataBase.sdf";
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(MainPage_Loaded);         


        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            WebClient webClient = new WebClient();
            webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
            webClient.DownloadStringAsync(new Uri("SomeURL"));
        }

        public void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            var rootObject = JsonConvert.DeserializeObject<RootObject1[]>(e.Result);

            foreach (var r in rootObject)
            {
                var s = r.detail.single_selection;
                for (int i = 0; i < s.Count; i++)
                {


                }
            }






        }


        public class RootObject1
        {
            public Detail detail { get; set; }
            [JsonProperty("total questions and marks")]
            public List<TotalQuestionsAndMark> totalquestionsandmarks { get; set; }
        }

        public class TotalQuestionsAndMark
        {
            [JsonProperty("total questions")]
            public int totalquestions { get; set; }
            [JsonProperty("total test marks")]
            public int totaltestmarks { get; set; }
            public string Duration { get; set; }
        }

        public class Detail
        {
            public List<SingleSelection> single_selection { get; set; }            
        }

        public class SingleSelection
        {
            public string Questions { get; set; }
            [JsonProperty("Question Type")]
            public string QuestionType { get; set; }
            public string Url { get; set; }
            public string marks { get; set; }
            public string description { get; set; }
            public Options option { get; set; }
            [JsonProperty("correct Ans")]
            public List<string> correctAns { get; set; }
        }

        public class Options
        {


            public string optionid { get; set; }
            public string option_name { get; set; }


        }
    }
}

我能够解析一些数据,但我不知道如何解析选项..请帮助我解析完整的代码。请帮助我解析完整的数据......提前谢谢......

【问题讨论】:

标签: c# json windows-phone-7 json.net


【解决方案1】:

您的代码的问题是您试图将键值对字典解析为对象项数组。

这是不可能的,因为解析引擎会认为 optionid 和 option_name 都是选项列表中每个对象项的属性。如果我们假设这些是属性,则属性必须有一个常量名称,而您的 json 中不是这种情况。

解析它的唯一可能方法是使用字符串/字符串的键值对字典。 您的代码必须是这样的,您应该删除 Options 类。

    [JsonProperty(PropertyName = "options")]
    public Dictionary<string, string> Options { get; set; } 

【讨论】:

    【解决方案2】:

    这是为您准备的示例转换器类:

    // Warning: untested code
    public class DictionaryConverter: JsonConverter
    {
        public override bool CanRead { get { return true; } }
        public override bool CanWrite { get { return false; } }
    
        public override bool CanConvert( Type objectType )
        {
            return objectType == typeof( Dictionary<string, string> );
        }
    
        public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
        {
            // Load JObject from stream
            JObject jObject = JObject.Load( reader );
            Dictionary<string, string> res = new Dictionary<string, string>( jObject.Count );
            foreach( var kvp in jObject )
                res[ kvp.Key ] = (string)kvp.Value;
            return res;
        }
    
        public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer )
        {
            throw new NotSupportedException();
        }
    }
    

    然后通过以下方式声明options字段/属性:

    [JsonProperty, JsonConverter( typeof( DictionaryConverter ) )]
    public Dictionary<string, string> options;
    

    附:您可能想要更改转换器以创建例如Dictionary&lt;int, string&gt; 或其他任何东西,而不仅仅是 Dictionary&lt;string, string&gt;

    【讨论】:

    • 你并不需要所有的代码,Newtonsoft 的 json 解析引擎已经支持 IDictionary 接口,不像微软的 DataContractJsonSerializer
    【解决方案3】:

    几个月前我遇到了类似的问题,基本上 JSON 使用的属性不能直接转换为 C# 属性。因此,经过一些研究,我找到了一种将这些属性反序列化为两个可能选项之一的方法(KeyValuePais 或 Dictioanry 的集合,它将取决于 JSON 哪个选项更适合)。

    顺便说一句,我正在使用 Json.NET 库,它可以让我自定义反序列化过程。

    这些是我正在使用的文件: 用于检索内容

    JsonRetriever.cs 使用 Newtonsoft.Json; 使用系统; 使用 System.Threading.Tasks;

    static class JsonRetriever
    {
    
        public async static Task<T> GetJsonFromUri<T>(string uriString)
        {
            var uri = new Uri(uriString);
            return await GetJsonFromUri<T>(uri);
        }
    
        public async static Task<T> GetJsonFromUri<T>(Uri uri)
        {
    
            var webRequest = System.Net.WebRequest.CreateHttp(uri);
            using (var webResponse = await Task<System.Net.WebResponse>.Factory.FromAsync(webRequest.BeginGetResponse, webRequest.EndGetResponse, TaskCreationOptions.None))
            {
                using (var stream = webResponse.GetResponseStream())
                {
                    return GetJson<T>(stream);
                }
            }
        }
    
        public static T GetJson<T>(System.IO.Stream stream)
        {
            using (var streamReader = new System.IO.StreamReader(stream))
            {
                using (var jsonTextReader = new JsonTextReader(streamReader))
                {
                    var jsonSerializer = JsonSerializer.CreateDefault();
                    var instanceOfT = jsonSerializer.Deserialize<T>(jsonTextReader);
                    return instanceOfT;
                }
            }
        }
    
        public static T GetJson<T>(System.String json)
        {
            using (System.IO.TextReader textReader = new System.IO.StringReader(json))
            {
                var jsonSerializer = JsonSerializer.CreateDefault();
                var instanceOfT = (T)jsonSerializer.Deserialize(textReader, typeof(T));
                return instanceOfT;
            }
        }
    }
    

    GenericJsonConverter.cs

     /// <summary>
        /// Indicates to Newtonsoft.Json how to deserialize:
        /// - interfaces to concrete classes
        /// - how to deserialize collections of interfaces to concrete classes
        /// - how to deserialize collections of KeyValuePairs (for non-valid identifiers JSON properties) into Dictionary or Collections
        /// See:
        ///      http://stackoverflow.com/questions/5780888/casting-interfaces-for-deserialization-in-json-net
        ///      http://stackoverflow.com/questions/9452901/cannot-deserialize-json-array-into-type-json-net
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TConcrete"></typeparam>
    public class GenericJsonConverter<TInterface, TConcrete> : JsonConverter where TConcrete : TInterface
    {
        public override bool CanConvert(Type objectType)
        {
            return
                 objectType == typeof(Collection<TInterface>)
              || objectType == typeof(TInterface)
              || objectType == typeof(Collection<KeyValuePair<string, TInterface>>)
              || objectType == typeof(Dictionary<string, TInterface>)
              ;
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (objectType == typeof(Collection<TInterface>))
            {
                return new Collection<TInterface>(serializer.Deserialize<Collection<TConcrete>>(reader).OfType<TInterface>().ToList());
            }
            if (objectType == typeof(TInterface))
            {
                return serializer.Deserialize<TConcrete>(reader);
            }
            if ((objectType == typeof(Collection<KeyValuePair<string, TInterface>>))
            || (objectType == typeof(Dictionary<string, TInterface>)))
            {
    
                var isDictionary = (objectType == typeof(Dictionary<string, TInterface>));
                Collection<KeyValuePair<string, TInterface>> deserializedObject = new Collection<KeyValuePair<string, TInterface>>();
    
                reader.Read(); // Skips the '{' token at the beginning of the JSON object
                while (reader.TokenType == JsonToken.PropertyName)
                {
                    var id = reader.Value.ToString();  // Contains the property value => for invalid JSONs properties it's an ID (e.g. number or GUID)
                    reader.Read(); // Skips the '{' token of the inner object
                    var instaceOfConcreteType = serializer.Deserialize<TConcrete>(reader);
                    deserializedObject.Add(new KeyValuePair<string, TInterface>(id, instaceOfConcreteType));
                    reader.Read(); // Skips the '{' token at the beginning of the JSON object
                }
                var result = isDictionary ? deserializedObject.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) : (object)deserializedObject;
                return result;
            }
    
            throw new NotSupportedException("Cannot Deserialize type:" + objectType);
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value == null)
                return;
            // TODO: Verify if value.GetType() is compatible with TConcrete before forcing a cast
            if (value.GetType() == typeof(TInterface))
                serializer.Serialize(writer, (TConcrete)value);
            throw new NotSupportedException("Cannot serialize type:" + value.GetType());
        }
    }
    

    Models.cs

    public class SingleSelection
    {
        public string Questions { get; set; }
        public string Url { get; set; }
        public string marks { get; set; }
        public string description { get; set; }
    
    
        [JsonConverter(typeof(GenericJsonConverter<string, string>))]
        public Dictionary<string, string> options { get; set; }
    
        [JsonProperty("Question Type")]
        public string QuestionType { get; set; }
    
        [JsonProperty("correct Ans")]
        public List<string> correctAns { get; set; }
    
    }
    
    public class Detail
    {
        public List<SingleSelection> single_selection { get; set; }
    }
    
    public class RootObject
    {
        public Detail detail { get; set; }
    }
    

    那么剩下的就是使用反序列化器了:

    var rootObject = JsonRetriever.GetJson<List<RootObject>>(AppResources.SampleJson);
    

    基本上,我们通过指示如何处理这些边缘情况来自定义序列化过程。顺便说一句,如果你想用接口支持你的具体类,GenericJsonConverter 也可以工作。

    这是 Windows Phone 8 的代码示例 https://dl.dropboxusercontent.com/u/7193016/stackoverflow/JsonSamplePhoneApp.zip

    问候, 赫伯

    【讨论】:

    • 感谢好友。很有帮助
    • 我想在我上次的测试中我意识到如果你只需要 Dictionary 那么你就不需要 GenericJsonConverter 。另一方面,如果你想使用 Dictionary 或 Dictionary 那么 GenericJsonConverter 是完全有用的;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 2021-01-08
    相关资源
    最近更新 更多