2013-04-10 9 views
196

Harici bir partiden alınan JSON dizesini takip ediyorum..NET NewtonSoft JSON, haritayı farklı bir özellik adına dönüştürür

{ 
    "team":[ 
     { 
     "v1":"", 
     "attributes":{ 
      "eighty_min_score":"", 
      "home_or_away":"home", 
      "score":"22", 
      "team_id":"500" 
     } 
     }, 
     { 
     "v1":"", 
     "attributes":{ 
      "eighty_min_score":"", 
      "home_or_away":"away", 
      "score":"30", 
      "team_id":"600" 
     } 
     } 
    ] 
} 

Benim haritalama sınıfları:

public class Attributes 
{ 
    public string eighty_min_score { get; set; } 
    public string home_or_away { get; set; } 
    public string score { get; set; } 
    public string team_id { get; set; } 
} 

public class Team 
{ 
    public string v1 { get; set; } 
    public Attributes attributes { get; set; } 
} 

public class RootObject 
{ 
    public List<Team> team { get; set; } 
} 

soru ben "Özellik sınıfı" gibi kalmamasıdır ve Takım sınıfında "alan adını bağlıyor". Bunun yerine, "TeamScore" olarak adlandırılmasını ve alan adlarından "_" öğelerini kaldırmasını ve uygun adlar vermesini istiyorum.

JsonConvert.DeserializeObject<RootObject>(jsonText); 

Ben bir "TeamScore" ile "Özellik" sınıfı değiştirebilir ama (Takım Class'ta nitelikleri) dosyalanmış adını değiştirirseniz, düzgün serisini olmayacak ve beni boş verir. Bunu nasıl aşabilirim?

cevap

403

Json.NET bir JSON özelliğin adını belirtmek sağlayan bir JsonPropertyAttribute sahiptir, bu nedenle kodu olmalıdır:

public class TeamScore 
{ 
    [JsonProperty("eighty_min_score")] 
    public string EightyMinScore { get; set; } 
    [JsonProperty("home_or_away")] 
    public string HomeOrAway { get; set; } 
    [JsonProperty("score ")] 
    public string Score { get; set; } 
    [JsonProperty("team_id")] 
    public string TeamId { get; set; } 
} 

public class Team 
{ 
    public string v1 { get; set; } 
    [JsonProperty("attributes")] 
    public TeamScore TeamScores { get; set; } 
} 

public class RootObject 
{ 
    public List<Team> Team { get; set; } 
} 

Dokümantasyon: Dinamik kullanmak isterseniz Serialization Attributes

+0

Berrak, özlü bir cevap. Güzel. Teşekkürler. Bana da yardım etti. FYI/Q ?: [JsonProperty ("takım) id" yazım hatası "] ... bir alt çizgi olmalı? – Aidanapword

+2

Bir dosya için iki JsonProperty kullanabilir miyim? –

+0

@AliYousefie Bunu düşünmeyin. Ama iyi soru, bundan ne elde etmeyi bekliyorsunuz? – outcoldman

65

eşleme ile modelinizi karıştırmak istemediğiniz için, bu yaklaşım benim için çalıştı

Kullanım:

var settings = new JsonSerializerSettings(); 
settings.DateFormatString = "YYYY-MM-DD"; 
settings.ContractResolver = new CustomContractResolver(); 
this.DataContext = JsonConvert.DeserializeObject<CountResponse>(jsonString, settings); 

Mantık:

public class CustomContractResolver : DefaultContractResolver 
{ 
    private Dictionary<string, string> PropertyMappings { get; set; } 

    public CustomContractResolver() 
    { 
     this.PropertyMappings = new Dictionary<string, string> 
     { 
      {"Meta", "meta"}, 
      {"LastUpdated", "last_updated"}, 
      {"Disclaimer", "disclaimer"}, 
      {"License", "license"}, 
      {"CountResults", "results"}, 
      {"Term", "term"}, 
      {"Count", "count"}, 
     }; 
    } 

    protected override string ResolvePropertyName(string propertyName) 
    { 
     string resolvedName = null; 
     var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName); 
     return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName); 
    } 
} 
+1

Amacım için biraz basitleştirdim ama bu daha iyi bir çözüm o zaman "modelinizi/alanınızı karıştırın";) – Andreas

+3

Vay. Bu epik; Bunu yapmanın daha mimari açıdan sağlam bir tarzı. –

+1

Bu (eğer bunlardan birden fazlasını oluşturursanız), tüm özellik eşlemeleri için söz dizimini yukarıdan bir temel sınıfa taşımayı ve özellik eklemelerine izin vermeyi, ancak eşlemenin nasıl yapıldığının ayrıntılarını görmezden gelmeyi deneyebilir. Bunu Json.Net’in kendisine eklemek de yeterli olabilir. –

3

krikolar çözeltisine eklenmesi. JsonProperty ve Serialize kullanarak JsonProperty'yi (veya tersi) göz ardı ederek Deserialize etmem gerekiyor. ReflectionHelper ve Attribute Helper, özelliklerin özelliklerinin veya özelliklerin bir listesini alan yardımcı sınıflardır. Birinin gerçekten umurunda olursa olabilirim. Aşağıdaki örneği kullanarak, JsonProperty "RecurringPrice" olmasına rağmen, viewmodel'i serileştirebilir ve "Tutar" ı alabilirsiniz.

/// <summary> 
    /// Ignore the Json Property attribute. This is usefule when you want to serialize or deserialize differently and not 
    /// let the JsonProperty control everything. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    public class IgnoreJsonPropertyResolver<T> : DefaultContractResolver 
    { 
     private Dictionary<string, string> PropertyMappings { get; set; } 

     public IgnoreJsonPropertyResolver() 
     { 
      this.PropertyMappings = new Dictionary<string, string>(); 
      var properties = ReflectionHelper<T>.GetGetProperties(false)(); 
      foreach (var propertyInfo in properties) 
      { 
       var jsonProperty = AttributeHelper.GetAttribute<JsonPropertyAttribute>(propertyInfo); 
       if (jsonProperty != null) 
       { 
        PropertyMappings.Add(jsonProperty.PropertyName, propertyInfo.Name); 
       } 
      } 
     } 

     protected override string ResolvePropertyName(string propertyName) 
     { 
      string resolvedName = null; 
      var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName); 
      return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName); 
     } 
    } 

Kullanımı:

 var settings = new JsonSerializerSettings(); 
     settings.DateFormatString = "YYYY-MM-DD"; 
     settings.ContractResolver = new IgnoreJsonPropertyResolver<PlanViewModel>(); 
     var model = new PlanViewModel() {Amount = 100}; 
     var strModel = JsonConvert.SerializeObject(model,settings); 

Modeli:

public class PlanViewModel 
{ 

    /// <summary> 
    ///  The customer is charged an amount over an interval for the subscription. 
    /// </summary> 
    [JsonProperty(PropertyName = "RecurringPrice")] 
    public double Amount { get; set; } 

    /// <summary> 
    ///  Indicates the number of intervals between each billing. If interval=2, the customer would be billed every two 
    ///  months or years depending on the value for interval_unit. 
    /// </summary> 
    public int Interval { get; set; } = 1; 

    /// <summary> 
    ///  Number of free trial days that can be granted when a customer is subscribed to this plan. 
    /// </summary> 
    public int TrialPeriod { get; set; } = 30; 

    /// <summary> 
    /// This indicates a one-time fee charged upfront while creating a subscription for this plan. 
    /// </summary> 
    [JsonProperty(PropertyName = "SetupFee")] 
    public double SetupAmount { get; set; } = 0; 


    /// <summary> 
    /// String representing the type id, usually a lookup value, for the record. 
    /// </summary> 
    [JsonProperty(PropertyName = "TypeId")] 
    public string Type { get; set; } 

    /// <summary> 
    /// Billing Frequency 
    /// </summary> 
    [JsonProperty(PropertyName = "BillingFrequency")] 
    public string Period { get; set; } 


    /// <summary> 
    /// String representing the type id, usually a lookup value, for the record. 
    /// </summary> 
    [JsonProperty(PropertyName = "PlanUseType")] 
    public string Purpose { get; set; } 
} 
+2

IgnoreJsonPropertyResolver'ınız için teşekkürler, aynı şeyi yapmak istediğim için (yalnızca serileştirme konusunda JsonProperty'i yoksay). Ne yazık ki çözümünüz sadece üst düzey nitelikler ve iç içe türler için çalışır. Serileştirme işleminde tüm JsonProperty özniteliklerini yok saymanın uygun yolu, ContractResolver'da 'CreateProperty' öğesini geçersiz kılmaktır. Orada baz çağrı: var jsonProperty = base.CreateProperty (memberInfo, memberSerialization); 've sonra jsonProperty.PropertyName = memberInfo.Name;'. Sonunda jsonProperty'ye dön, 'İhtiyacınız olan bu kadar. –

+0

Bu yardımcılar nelerdir? – deadManN

+1

@NateCook bana bir örnek gösterebilir misin? ona çok ihtiyacım var – deadManN

1

birçok türde bir bütün grafiği halledilir edilecek senaryolarda, Rentering.com's cevap genişletilmesi ve aradığınız Güçlü bir şekilde yazılan bir çözüm için, bu sınıf aşağıdakilere yardımcı olabilir (aşağıdaki kullanımı) (akıcı). Tür başına siyah liste veya beyaz liste olarak çalışır. Bir tür (ikisi de olamaz (Gist - aynı zamanda global göz ardı listesi içerir).

public class PropertyFilterResolver : DefaultContractResolver 
{ 
    const string _Err = "A type can be either in the include list or the ignore list."; 
    Dictionary<Type, IEnumerable<string>> _IgnorePropertiesMap = new Dictionary<Type, IEnumerable<string>>(); 
    Dictionary<Type, IEnumerable<string>> _IncludePropertiesMap = new Dictionary<Type, IEnumerable<string>>(); 
    public PropertyFilterResolver SetIgnoredProperties<T>(params Expression<Func<T, object>>[] propertyAccessors) 
    { 
    if (propertyAccessors == null) return this; 

    if (_IncludePropertiesMap.ContainsKey(typeof(T))) throw new ArgumentException(_Err); 

    var properties = propertyAccessors.Select(GetPropertyName); 
    _IgnorePropertiesMap[typeof(T)] = properties.ToArray(); 
    return this; 
    } 

    public PropertyFilterResolver SetIncludedProperties<T>(params Expression<Func<T, object>>[] propertyAccessors) 
    { 
    if (propertyAccessors == null) 
     return this; 

    if (_IgnorePropertiesMap.ContainsKey(typeof(T))) throw new ArgumentException(_Err); 

    var properties = propertyAccessors.Select(GetPropertyName); 
    _IncludePropertiesMap[typeof(T)] = properties.ToArray(); 
    return this; 
    } 

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
    var properties = base.CreateProperties(type, memberSerialization); 

    var isIgnoreList = _IgnorePropertiesMap.TryGetValue(type, out IEnumerable<string> map); 
    if (!isIgnoreList && !_IncludePropertiesMap.TryGetValue(type, out map)) 
     return properties; 

    Func<JsonProperty, bool> predicate = jp => map.Contains(jp.PropertyName) == !isIgnoreList; 
    return properties.Where(predicate).ToArray(); 
    } 

    string GetPropertyName<TSource, TProperty>(
    Expression<Func<TSource, TProperty>> propertyLambda) 
    { 
    if (!(propertyLambda.Body is MemberExpression member)) 
     throw new ArgumentException($"Expression '{propertyLambda}' refers to a method, not a property."); 

    if (!(member.Member is PropertyInfo propInfo)) 
     throw new ArgumentException($"Expression '{propertyLambda}' refers to a field, not a property."); 

    var type = typeof(TSource); 
    if (!type.GetTypeInfo().IsAssignableFrom(propInfo.DeclaringType.GetTypeInfo())) 
     throw new ArgumentException($"Expresion '{propertyLambda}' refers to a property that is not from type '{type}'."); 

    return propInfo.Name; 
    } 
} 

Kullanımı:

var resolver = new PropertyFilterResolver() 
    .SetIncludedProperties<User>(
    u => u.Id, 
    u => u.UnitId) 
    .SetIgnoredProperties<Person>(
    r => r.Responders) 
    .SetIncludedProperties<Blog>(
    b => b.Id) 
    .Ignore(nameof(IChangeTracking.IsChanged)); //see gist