2017-09-28 24 views
5

Khi deserializing một đối tượng JSON thành một Net type, nếu tên trường không phù hợp tôi thấy bạn có thể trang trí tính type của bạn với [JsonProperty(PropertyName = "name")]Làm cách nào để áp dụng quy tắc chung cho việc ánh xạ lại tất cả tên thuộc tính khi tuần tự hóa với Json.NET?

Đây là tiền phạt và dandy cho một vài tính năng mà don không phù hợp, nhưng có cách nào để thiết lập quy ước hay quy tắc không?

Json

{ 
    "Job": [ 
    { 
     "Job #": "1", 
     "Job Type": "A", 
    } 
    ] 
} 

C#

[JsonProperty(PropertyName = "Job Type")] 
    public string JobType { get; set; } 

    [JsonProperty(PropertyName = "Job #")] 
    public string JobNumber { get; set; } 

Tôi có nhiều lĩnh vực sử dụng tên tương tự, những gì tôi muốn tìm ra, là có một cách để nói để thiết lập một quy tắc để luôn loại bỏ dấu cách (EG: Job Type -> JobType) và thay thế # bằng Number (ví dụ: Job # -> JobNumber)?

Có vẻ như một tùy chỉnh ContractResolver có thể là giải pháp duy nhất, nhưng tôi không thể tìm ra cách sử dụng nó để nhổ ra các khoảng trống và thay thế "#" bằng "Số". Có ai có một ví dụ tham khảo?

Hoặc tôi hy vọng có một giải pháp đơn giản mà tôi đã bỏ qua.

P.S. Đồng thời chấp nhận đề xuất cho một tiêu đề tốt hơn.

+1

Đối với tiêu đề, cách * Cách áp dụng quy tắc chung để ánh xạ lại tất cả tên thuộc tính khi tuần tự hóa với Json.NET?* – dbc

Trả lời

2

Giả sử bạn đang làm việc với Json.NET 9.0.1 hoặc mới hơn, điều này có thể được thực hiện với tùy chỉnh NamingStrategy.Ví dụ, đây là một dựa trên SnakeCaseNamingStrategyStringUtils.ToSnakeCase() James Newton-King:

public class CustomNamingStrategy : NamingStrategy 
{ 
    public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames) 
    { 
     ProcessDictionaryKeys = processDictionaryKeys; 
     OverrideSpecifiedNames = overrideSpecifiedNames; 
    } 

    public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames) 
     : this(processDictionaryKeys, overrideSpecifiedNames) 
    { 
     ProcessExtensionDataNames = processExtensionDataNames; 
    } 

    public CustomNamingStrategy() 
    { 
    } 

    protected override string ResolvePropertyName(string name) 
    { 
     return SpaceWords(name); 
    } 

    enum WordState 
    { 
     Start, 
     Lower, 
     Upper, 
     NewWord 
    } 

    static string SpaceWords(string s) 
    { 
     // Adapted from StringUtils.ToSnakeCase() 
     // https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Utilities/StringUtils.cs#L191 
     // 
     // Copyright (c) 2007 James Newton-King 
     // 
     // Permission is hereby granted, free of charge, to any person 
     // obtaining a copy of this software and associated documentation 
     // files (the "Software"), to deal in the Software without 
     // restriction, including without limitation the rights to use, 
     // copy, modify, merge, publish, distribute, sublicense, and/or sell 
     // copies of the Software, and to permit persons to whom the 
     // Software is furnished to do so, subject to the following 
     // conditions: 
     // 
     // The above copyright notice and this permission notice shall be 
     // included in all copies or substantial portions of the Software. 
     // 
     // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
     // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
     // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
     // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
     // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
     // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
     // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
     // OTHER DEALINGS IN THE SOFTWARE. 

     char wordBreakChar = ' '; 

     if (string.IsNullOrEmpty(s)) 
     { 
      return s; 
     } 

     StringBuilder sb = new StringBuilder(); 
     WordState state = WordState.Start; 

     for (int i = 0; i < s.Length; i++) 
     { 
      if (s[i] == ' ') 
      { 
       if (state != WordState.Start) 
       { 
        state = WordState.NewWord; 
       } 
      } 
      else if (char.IsUpper(s[i])) 
      { 
       switch (state) 
       { 
        case WordState.Upper: 
         bool hasNext = (i + 1 < s.Length); 
         if (i > 0 && hasNext) 
         { 
          char nextChar = s[i + 1]; 
          if (!char.IsUpper(nextChar) && nextChar != ' ') 
          { 
           sb.Append(wordBreakChar); 
          } 
         } 
         break; 
        case WordState.Lower: 
        case WordState.NewWord: 
         sb.Append(wordBreakChar); 
         break; 
       } 

       sb.Append(s[i]); 

       state = WordState.Upper; 
      } 
      else if (s[i] == wordBreakChar) 
      { 
       sb.Append(wordBreakChar); 
       state = WordState.Start; 
      } 
      else 
      { 
       if (state == WordState.NewWord) 
       { 
        sb.Append(wordBreakChar); 
       } 

       sb.Append(s[i]); 
       state = WordState.Lower; 
      } 
     } 

     sb.Replace("Number", "#"); 
     return sb.ToString(); 
    } 
} 

Sau đó, bạn có thể áp dụng nó vào loại bạn như sau:

[JsonObject(NamingStrategyType = typeof(CustomNamingStrategy))] 
public class RootObject 
{ 
    public string JobType { get; set; } 

    public string JobNumber { get; set; } 

    public int JobItemCount { get; set; } 

    public string ISOCode { get; set; } 

    public string SourceXML { get; set; } 
} 

Và JSON được tạo ra sẽ được như sau:

{ 
    "Job Type": "job type", 
    "Job #": "01010101", 
    "Job Item Count": 3, 
    "ISO Code": "ISO 9000", 
    "Source XML": "c:\temp.xml" 
} 

Ghi chú:

  • Nếu bạn muốn chiến lược áp dụng cho các thuộc tính đã có tên thuộc tính được chỉ định qua JsonPropertyAttribute.PropertyName, hãy đặt NamingStrategy.OverrideSpecifiedNames == true.

  • Để áp dụng chiến lược đặt tên cho tất cả các loại thay vì đặt nó trên từng đối tượng, bạn có thể đặt chiến lược đặt tên trong DefaultContractResolver.NamingStrategy, sau đó đặt trình phân giải hợp đồng theo số JsonSerializerSettings.ContractResolver.

  • Bản đồ chiến lược đặt tên từ tên thuộc tính C# đến tên thuộc tính JSON, chứ không phải ngược lại. Vì vậy, bạn cần chèn khoảng trắng thay vì "nhổ chúng ra" và thay thế "Số" bằng "#". Ánh xạ sau đó được lưu trữ bởi trình giải quyết hợp đồng và tra cứu ngược được thực hiện trong quá trình deserialization.

1

Có một ContractResolver là cách để thực hiện.

Vấn đề là những điều này dường như chỉ hoạt động từ tài sản đích đến nguồn, tức là "JobType" -> "Job Type", không theo cách khác như bạn muốn. Điều này làm cho giải pháp một chút flaky hơn bạn có thể muốn.

Đầu tiên chúng ta thực hiện ContractResolver của chúng tôi, kế thừa từ DefaultContractResolver, vì vậy nó tất cả các công trình như bình thường ngoài các bit chúng ta muốn tùy chỉnh:

public class JobContractResolver : DefaultContractResolver 
{ 
    protected override string ResolvePropertyName(string propertyName) 
    { 
     // first replace all capital letters with space then letter ("A" => " A"). This might include the first letter, so trim the result. 
     string result = Regex.Replace(propertyName, "[A-Z]", x => " " + x.Value).Trim(); 

     // now replace Number with a hash 
     result = result.Replace("Number", "#"); 

     return result; 
    } 
} 

Sau đó, trong deserialization của chúng tôi, chúng tôi đặt ContractResolver trong JsonSerializerSettings:

static void Main(string[] args) 
{ 
    string input = @"{""Job #"": ""1"", ""Job Type"": ""A""}"; 

    var job1 = JsonConvert.DeserializeObject<Job1>(input, new JsonSerializerSettings 
    { 
     ContractResolver = new JobContractResolver() 
    }); 

    Console.WriteLine("JobType: {0}", job1.JobType); 
    Console.WriteLine("JobNumber: {0}", job1.JobNumber); 
} 
Các vấn đề liên quan