简体   繁体   中英

How to parse a json object array containing mixed primitive types using DataContractJsonSerializer?

How can I parse the JSON object below using DataContractJsonSerializer in C#?

I will need to define a class to hold the below JSON data, which includes an array of arrays of primitives of mixed types (string and integer):

Body:
    {
      "status": "failure",
      "staticdata": [
        [
          "2013-06-01",
          123
        ],
        [
          "2013-06-02",
          234
        ],
        [
          "2013-06-03",
          345
        ],    
        ...
      ]
    }

I tried the below answer and tried to read through DataContractJsonSerializer ,

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));

object objResponse = jsonSerializer.ReadObject(response);

RootObject jsonResponse = objResponse as RootOject;

foreach (object[] sd in jsonResponse.staticdata)
{
    foreach (object o in sd)
    {
        //Value val = v as Value;
        Value val = (Value)Convert.ChangeType(o, typeof(Value));
            log.Info("date: " + val.date);
            log.Info("crashCount: " + val.longValue);
   }
} 

but in converttype from object to Value is crashing, am I missing something here.

Value is below class:

[DataContract]
public class Value
{
    [DataMember(Name = "date")]
    public string date { get; set; }

    [DataMember(Name = "longValue")]
    public long longValue{ get; set; }
}

modified code read Values (IgnoreDataMember Values), and then could able to read as below: is this the right approach?

object objResponse = jsonSerializer.ReadObject(response);

RootObject jsonResponse = objResponse as RootOject;

foreach (Value in jsonResponse.Values)
{
            log.Info("date: " + val.date);
            log.Info("longValue: " + val.longValue);
} 

If you just want to deserialize your JSON, you can use a code-generation tool like http://json2csharp.com/ or Paste JSON As Classes and get the following data model, which works perfectly well with DataContractJsonSerializer :

public class RootObject
{
    public string status { get; set; }
    public List<List<object>> staticdata { get; set; }
}

object works because DataContractJsonSerializer automatically recognizes and serializes known primitive types such as string and int .

But what you may want is to deserialize your "staticdata" array to a list of classes such as this:

public class Value
{
    public string Date { get; set; }
    public int IntValue { get; set; }
}

If so, you can make use of a surrogate property in the RootObject type to do the conversion:

[DataContract]
public class RootObject
{
    [DataMember]
    public string status { get; set; }

    [DataMember]
    object[][] staticdata
    {
        get
        {
            if (Values == null)
                return null;
            return Values.Select(v => new object[] { v.Date, v.IntValue }).ToArray();
        }
        set
        {
            if (value == null)
                return;
            Values = value.Select(a => new Value 
                { 
                    Date = a.Length < 1 ? null : (string)Convert.ChangeType(a[0], typeof(string), CultureInfo.InvariantCulture),
                    IntValue = a.Length < 2 ? 0 : (int)Convert.ChangeType(a[1], typeof(int), CultureInfo.InvariantCulture) 
                }
                ).ToList();
        }
    }

    [IgnoreDataMember]
    public List<Value> Values { get; set; }
}

Update

In your updated question you asked, but in converttype from object to Value is crashing, am I missing something here?

Your problem is that you are trying to use Convert.ChangeType() to convert an object to a Value , but this method is only for primitive data types that can be converted from and to strings. From the docs :

ChangeType is a general-purpose conversion method that converts the object specified by value to conversionType. The value parameter can be an object of any type, and conversionType can also be a Type object that represents any base or custom type. For the conversion to succeed, value must implement the IConvertible interface, because the method simply wraps a call to an appropriate IConvertible method.

As your Value type does not implement this interface, conversion fails.

Instead, you should use Convert.ChangeType on the individual entries in the nested arrays. Given your RootObject looks like:

public class RootObject
{
    public string status { get; set; }
    public object [][] staticdata { get; set; }
}

You should do:

using System.Linq;

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));
var jsonResponse = (RootObject)jsonSerializer.ReadObject(response);

var query = jsonResponse.staticdata
    // For each object [] array in the outer array
    .Select(a => new Value
        {
             // Convert the inner array to a Value, using the first element for the date and the second element for the longValueand the second element for the longValue
            date = a.Length < 1 ? null : (string)Convert.ChangeType(a[0], typeof(string), CultureInfo.InvariantCulture),
            longValue = a.Length < 2 ? 0 : (long)Convert.ChangeType(a[1], typeof(long), CultureInfo.InvariantCulture)
        });

foreach (var val in query)
{
    log.Info("date: " + val.date);
    log.Info("crashCount: " + val.longValue);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM