Newtonsoft JSON.NET parse to array of custom key/value pair objects

后端 未结 2 607
春和景丽
春和景丽 2020-12-22 03:31

I have this strange issue with parsing given JSON data. I have this JSON structure:

{\"value\":[
  {\"street\":\"Karlova 25\"},
  {\"city\":\"Prague\"},
  {\         


        
相关标签:
2条回答
  • 2020-12-22 04:01

    You don't need to reinvent the wheel. This funcionality is already working. Create classes like below:

    public class Value
    {
        public string street { get; set; }
        public string city { get; set; }
        public string gpsLat { get; set; }
        public string gpsLon { get; set; }
    }
    
    public class MyClass
    {
        public List<Value> value { get; set; }
    }
    

    Now You can simply deserialize your json to your poco object.

    MyClass result  = JsonConvert.DeserializeObject<MyClass>(youJson);
    
    0 讨论(0)
  • 2020-12-22 04:22

    It appears that you want to represent a Dictionary<string, string> in your JSON as an array of objects, where each nested object has one key and value from the dictionary. You can do it with the following converter:

    public class DictionaryToDictionaryListConverter<TKey, TValue> : JsonConverter 
    {
        class DictionaryDTO : Dictionary<TKey, TValue>
        {
            public DictionaryDTO(KeyValuePair<TKey, TValue> pair) : base(1) { Add(pair.Key, pair.Value); }
        }
    
        public override bool CanConvert(Type objectType)
        {
            return typeof(IDictionary<TKey, TValue>).IsAssignableFrom(objectType) && objectType != typeof(DictionaryDTO);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var token = JToken.Load(reader);
            var dict = (IDictionary<TKey, TValue>)(existingValue as IDictionary<TKey, TValue> ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
            if (token.Type == JTokenType.Array)
            {
                foreach (var item in token)
                    using (var subReader = item.CreateReader())
                        serializer.Populate(subReader, dict);
            }
            else if (token.Type == JTokenType.Object)
            {
                using (var subReader = token.CreateReader())
                    serializer.Populate(subReader, dict);
    
            }
            return dict;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var dict = (IDictionary<TKey, TValue>)value;
            // Prevent infinite recursion of converters by using DictionaryDTO
            serializer.Serialize(writer, dict.Select(p => new DictionaryDTO(p)));
        }
    }
    

    Then use it in your container class as follows:

    public class RootObject
    {
        [JsonProperty("value")]
        [JsonConverter(typeof(DictionaryToDictionaryListConverter<string, string>))]
        public Dictionary<string, string> Value { get; set; }
    }
    

    Note that the converter will throw an exception during reading if the keys are not unique.

    Update

    For AddressValue you could use the following converter:

    public class AddressValueConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(AddressValue);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var addressValue = (existingValue as AddressValue ?? new AddressValue());
            var token = JObject.Load(reader);
            var property = token.Properties().SingleOrDefault();
            if (property != null)
            {
                addressValue.Label = property.Name;
                addressValue.Value = (string)property.Value;
            }
            return addressValue;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var addressValue = (AddressValue)value;
            serializer.Serialize(writer, new Dictionary<string, string> { { addressValue.Label, addressValue.Value } });
        }
    }
    

    Then use it as follows:

    [JsonConverter(typeof(AddressValueConverter))]
    public class AddressValue
    {
        public string Label { get; set; }
        public string Value { get; set; }
    }
    
    public class RootObject
    {
        [JsonProperty("value")]
        public List<AddressValue> Value { get; set; }
    }
    

    Demo fiddle with both options here.

    0 讨论(0)
提交回复
热议问题