2017-05-30 23 views
2

我有一些包含有點奇怪格式的JSON文件。我必須閱讀,修改和保存我的項目的這種格式。不幸的是,我對給定的格式沒有任何影響。有選擇地將實例的屬性序列化爲JSON

這種格式的奇怪之處在於,這個結構中的所有實體都有一個唯一的標識符,它被無效地稱爲「$ id」。這些實例也可以通過它們的id來引用,而不是完整的屬性集。在這種情況下,沒有「$ id」,而是有一個「$ ref」字段,其中包含一個已經定義的實體。看看下面的(縮短)例如:

{ 
    "$id": "1", 
    "StyleName": "Standard", 
    "Style": { 
     "$id": "2", 
     "ShapeStyle": { 
      "$id": "3", 
      "Background": { 
       "$id": "4", 
       "Color": { 
        "$id": "5", 
        "A": 255, 
        "R": 68, 
        "G": 84, 
        "B": 106 
       } 
      } 
     }, 
     "RightEndCapsStyle": { 
      "$id": "6", 
      "Background": { 
       "$id": "7", 
       "Color": { 
        "$ref": "5" 
       } 
      } 
     } 
    } 
} 

爲了解決這個問題,我創建了一個C#基類實體所有JSON數據類。這個基類維護一個ID的註冊表,以便它可以很容易地找到一個給定的實例$ ref。下面的代碼:

public class Entity 
{ 
    public static Dictionary<string, Entity> Registry = new Dictionary<string, Entity>(); 

    private string key = string.Empty; 

    [JsonProperty("$id", Order = -2)] 
    [DefaultValue("")] 
    public string Key 
    { 
     get { return key; } 
     set 
     { 
      key = value; 
      if (!string.IsNullOrEmpty(key)) Registry.Add(key, this); 
     } 
    } 

    [JsonProperty("$ref")] 
    public string RefKey { get; set; } 

    [JsonIgnore] 
    public bool IsReference => !string.IsNullOrEmpty(RefKey); 

    [JsonIgnore] 
    public Entity RefEntity 
    { 
     get 
     { 
      Entity entity = null; 
      if (IsReference && !Registry.TryGetValue(RefKey, out entity)) 
      { 
       throw new ApplicationException("Referenced entity not found!"); 
      } 
      return entity; 
     } 
    } 
} 

的JSON類hiearchy看起來是這樣的:

public class RootObject: Entity 
{ 
    public string StyleName { get; set; } 
    public StyleRoot Style { get; set; } 
} 

public class StyleRoot: Entity 
{ 
    public Style ShapeStyle { get; set; } 
    public Style RightEndCapsStyle { get; set; } 
} 

public class Style: Entity 
{ 
    public Background Background { get; set; } 
} 

public class Background: Entity 
{ 
    public Color Color { get; set; } 
} 

public class Color: Entity 
{ 
    public int A { get; set; } 
    public int R { get; set; } 
    public int G { get; set; } 
    public int B { get; set; } 
} 

到目前爲止,一切都很好。現在我的問題:

  1. [JsonProperty("$id")][JsonProperty("$ref")]不工作,因爲的$ id$裁判沒有有效的JSON字段名標識符。目前,我正在使用正則表達式將其替換爲有效的內容,然後將它們重新替換爲之前的內容。但是,這是緩慢的。我想知道是否可以使用NamingStrategy來達到同樣的效果。但我沒有成功。記住,我需要兩種方式,反序列化和序列化。
  2. 序列化是一個更難的問題。如果我按照原樣序列化結構,那麼在每個實例中,我最終都會得到"$id":"$ref":字段。更重要的是,與所引用的項目一起,所有其他字段都使用默認值進行序列化。最簡單的方法是在JsonSerializerSettings中簡單地設置DefaultValueHandling.IgnoreAndPopulate。但是這樣,所有的默認值都會從輸出中剝離,導致意外的行爲。我試圖用ContractResolver去,但因爲這是當前屬性本地,並且不能考慮周圍的實體,所以失敗了。有沒有其他方法來實現自定義序列化策略?

這個問題很難說,我知道。還有很多東西需要閱讀和理解。但如果這很容易,我不會花費精力把它放在這裏。迫切需要你的幫助。

回答

1

這些$id S和$ref s的使用Json.NET內部時被啓用PreserveReferencesHandling mode。您無需關心它們,只需定義您的RootObject,StyleRoot等類別即可,無需Entity基類,並在JsonSerializerSettings中設置PreserveReferencesHandling模式。 JSON。NET將處理引擎蓋下$id S和$ref S和創建對象的網絡保留原始參考結構:

var obj = JsonConvert.DeserializeObject<RootObject>(json, 
    new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All }); 

序列化也可以在保持引用來完成的不同處理方式:

var json = JsonConvert.SerializeObject(obj, 
    new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects }); 

演示:https://dotnetfiddle.net/TygMDZ

NB在您的輸入數據示例中,"$ref"屬性包含一個數字值,而Json.NET寫入和期望"$ref"屬性具有字符串值。可能是因爲你在一些實驗過程中意外地發佈了改變的JSON文本呢?

+0

完美!適用於我。 你對「$ ref」的價值是正確的。我已經剝去了很多文字,使它更加緊湊。我不得不做一些手動編輯... 順便說一句,PreserveReferenceHandling.Object和PreserveReferenceHandling.All有什麼區別? – freefall

相關問題