Deserialize Json where the key is a number

9

I'm trying to deserialize Json with C #, but I've encountered a problem. In Json you can use numbers in the names of "keys" ( keys ), but we can not use numbers in property names in C #

Example:

Json :

"c":[  
  {  
     "1":23200083,
     "2":"string aleatória",
     "3":0,
     "4":19,
     "5":0,
     "7":9,
     "8":0,
     "9":0,
     "10":0,
     "11":33,
     "12":0,
     "13":999,
     "14":36,
     "15":0,
     "16":1,
     "6":0,
     "17":0
  }
]

C # :

public class C
{

    public string 1 { get; set; }
    public string 2 { get; set; }
    ...
}

I tried to use [JsonProperty(PropertyName = "2"]) , but the code still does not work.

    
asked by anonymous 03.02.2016 / 01:02

2 answers

8

First, for json to be valid I had to make some adjustments to be as below:

{
"c":[  
  {  
     "1":23200083,
     "2":"string aleatória",
     "3":0,
     "4":19,
     "5":0,
     "7":9,
     "8":0,
     "9":0,
     "10":0,
     "11":33,
     "12":0,
     "13":999,
     "14":36,
     "15":0,
     "16":1,
     "6":0,
     "17":0
  }]
}

For class json to work, I did this example (I just did the first two json attributes, but then you just follow the idea):

public class CJson
{
    public List<NumericJson> c { get; set; }
}

public class NumericJson
{
    [JsonProperty("1")]
    public int Item1 { get; set; }

    [JsonProperty("2")]
    public string Item2 { get; set; }
}

And the reading and confirmation that is working I made by application console, with this code:

    CJson jsonCObject = Newtonsoft.Json.JsonConvert.DeserializeObject<CJson>(jsonToDeserialize);
    Console.WriteLine(jsonCObject.c[0].Item1);
    Console.WriteLine(jsonCObject.c[0].Item2);

If you need a reference see this question 'Access JSON fields with numeric keys '

    
03.02.2016 / 01:22
1

Using a JsonConverter you can deserialize this json into a property of type Dictionary<string,string> or a List<Item> , with class Item declared this way:

public class Item
{
    //Note que o nome das propriedades pode ser outro qualquer.
    public string Key { get;}
    public string Value { get;}

    public Item(string key, string value)
    {
        Key = key;
        Value = value;
    }
}

The advantage is that whatever the number of pairs "key":"value" , the class to receive the result is always the same.

The only drawback is that the deserialized integer values will have to be converted to string , which I do not think is an impediment to using the result.

Deserialize to Dictionary<string,string> :

Class to receive deserialization result.

public class CJson
{
    [JsonConverter(typeof(MapJsonConverter))]
    public Dictionary<string, string> C { get; set; }
}

Json Class Converter.

public class MapJsonConverter : JsonConverter
{

    public override object ReadJson(JsonReader reader, Type objectType,
                                    object existingValue, JsonSerializer serializer)
    {
        if (!CanConvert(objectType))
        {
            throw new InvalidCastException(
                string.Format($"Can't cast from {objectType} to {typeof (Dictionary<string, string>)}");
        }

        if (reader.TokenType == JsonToken.StartArray)
        {
            var map = new Dictionary<string, string>();
            reader.Read();//Start object
            reader.Read();//Object
            while (reader.TokenType != JsonToken.EndArray)
            {
                if (reader.TokenType == JsonToken.PropertyName)
                {
                    var key = reader.Value.ToString();
                    reader.Read();//Next Token
                    var value = reader.Value.ToString();
                    map.Add(key,value);
                }
                reader.Read();//Next Token
            }
            return map;
        }
        throw new InvalidOperationException("Unexpected Json content");
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(Dictionary<string, string>).IsAssignableFrom(objectType);
    }

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

}

Note: If the set of "key":"value" pairs had all values of the same type, deserialization could be done directly on a List<Dictionary<string, string>> property, without needing a JsonConverter .

Deserialize to List<Item> :

Class to receive deserialization result.

public class CJson
{
    [JsonConverter(typeof(MapJsonConverter))]
    public IList<Item> C { get; set; }
}

Json Class Converter.

public class MapJsonConverter : JsonConverter
{

    public override object ReadJson(JsonReader reader, Type objectType,
                                    object existingValue, JsonSerializer serializer)
    {
        if (!CanConvert(objectType))
        {
            throw new InvalidCastException(
                string.Format($"Can't cast from {objectType} to {typeof (List<Item>)}");
        }

        if (reader.TokenType == JsonToken.StartArray)
        {
            var list = new List<Item>();
            reader.Read();//Start object
            reader.Read();//Object
            while (reader.TokenType != JsonToken.EndArray)
            {
                if (reader.TokenType == JsonToken.PropertyName)
                {
                    var key = reader.Value.ToString();
                    reader.Read();//Next Token
                    var value = reader.Value.ToString();
                    var item = new Item(key, value);
                    list.Add(item);
                }
                reader.Read();//Next Token
            }
            return list;
        }
        throw new InvalidOperationException("Unexpected Json content");
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(IList<Item>).IsAssignableFrom(objectType) ||
               typeof(List<Item>).IsAssignableFrom(objectType);
    }

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

}

In both cases, use

CJson result = JsonConvert.DeserializeObject<CJson>(jsonString);

to deserialize.

    
18.08.2016 / 00:43