Deserialize Json in which the key is a number

Asked

Viewed 424 times

10

I’m trying to deserialize Json with C#, but I found a problem. In Json you can use numbers in the names of "keys" (keys), but we can’t 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 still the code doesn’t work.

2 answers

9


First, for json to be valid I had to make some adjustments to stay 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 the json class to work, I did according to this example (I only did for 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 did by console application, 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 in English see this question 'Access JSON Fields with Numeric Keys'

2

Used a Jsonconverter it is possible to deserialize this json on a property of the type Dictionary<string,string> or in a List<Item>, with class Item stated in 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 whole values will have to be converted to string, which I believe is not an impediment to the use of the result.

Deserialize to Dictionary<string,string>:

Class to receive the result of deserialization.

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 pairs "key":"value" had the values(value) all of the same type, the deserialization could be done directly in a property of the type List<Dictionary<string, string>>, without the need for a Jsonconverter.

Deserialize to List<Item>:

Class to receive the result of deserialization.

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.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.