2015-10-08 21 views
8

Ben dinlendirici web servisleri çağırmak için bir şablonun olarak kullanılan bir JObject var JObject serileştirirler. Bu JObject, bir ayrıştırıcı yoluyla oluşturulur ve kullanıcı, bitiş noktası şemasının neye benzediğini anlatan bir şablon olarak kullanıldığından, tüm özelliklerini korumanın bir yolunu bulmak zorunda kaldım, bu yüzden değerlerini null olarak ayarlıyorum.JSON.NET

{ 
    "Foo":{ 
     "P1":null, 
     "P2":"hello world", 
     "P3":null, 
     "P4":{ 
     "P1":1, 
     "P2":null, 
     "P3":null, 
     }, 
     "FooArray":[ 
     { 
      "F1":null, 
      "F2":null, 
      "F3":null, 
     } 
     ] 
    }, 
    "Bar":null 
} 

onlar sadece anlam: Böyle Foo.P2 ve Foo.P4.P1 olarak, ihtiyaç duydukları gibi kullanıcı daha sonra tek tek alanları doldurun yapabiliyor

{ 
    "Foo":{ 
     "P1":null, 
     "P2":null, 
     "P3":null, 
     "P4":{ 
     "P1":null, 
     "P2":null, 
     "P3":null, 
     }, 
     "FooArray":[ 
     { 
      "F1":null, 
      "F2":null, 
      "F3":null, 
     } 
     ] 
    }, 
    "Bar":null 
} 

: örnek olarak, bu gibi nesne özgün görünüyor budur Bu iki alana dikkat edin. Şimdi bu şablonu (JObject) bir JSON dizisine serileştirmek istiyorum, ancak yalnızca gösterilmek üzere doldurulmuş olan alanları istiyorum. Bu yüzden şunu denedim: Bu işe yaramadı Maalesef, bu işe yaramadı. this question ile karşılaştım ve nesnede bir null değerinin gerçek bir JToken türü olduğunu ve gerçekten bir null olduğunu fark ettiniz, bu da mantıklı. Ancak, bu çok özel durumda, bu "kullanılmayan" alanlardan kurtulmam gerekiyor. El düğümleri üzerinde yinelenen ve bunları kaldırarak denedim ama bu da işe yaramadı. Kullandığım tek yönetilen türün JObject olduğunu unutmayın; Bu "şablon" çalışma zamanında çözüldüğü için, nesneyi niteliklere dönüştürmek veya tanımlamak için bir modelim yok. Sadece birinin böyle bir sorunla karşılaşıp karşılaşmadığını ve herhangi bir kavrayışı olup olmadığını merak ediyordum. Herhangi bir yardım büyük beğeni topluyor!

cevap

11

null değerlerini serileştirmeden önce JToken hiyerarşinizden kaldırmak için aşağıdaki gibi bir özyinelemeli yardımcı yöntem kullanabilirsiniz.

using System; 
using Newtonsoft.Json.Linq; 

public static class JsonHelper 
{ 
    public static JToken RemoveEmptyChildren(JToken token) 
    { 
     if (token.Type == JTokenType.Object) 
     { 
      JObject copy = new JObject(); 
      foreach (JProperty prop in token.Children<JProperty>()) 
      { 
       JToken child = prop.Value; 
       if (child.HasValues) 
       { 
        child = RemoveEmptyChildren(child); 
       } 
       if (!IsEmpty(child)) 
       { 
        copy.Add(prop.Name, child); 
       } 
      } 
      return copy; 
     } 
     else if (token.Type == JTokenType.Array) 
     { 
      JArray copy = new JArray(); 
      foreach (JToken item in token.Children()) 
      { 
       JToken child = item; 
       if (child.HasValues) 
       { 
        child = RemoveEmptyChildren(child); 
       } 
       if (!IsEmpty(child)) 
       { 
        copy.Add(child); 
       } 
      } 
      return copy; 
     } 
     return token; 
    } 

    public static bool IsEmpty(JToken token) 
    { 
     return (token.Type == JTokenType.Null); 
    } 
} 

Demo:

string json = @" 
{ 
    ""Foo"": { 
     ""P1"": null, 
     ""P2"": ""hello world"", 
     ""P3"": null, 
     ""P4"": { 
      ""P1"": 1, 
      ""P2"": null, 
      ""P3"": null 
     }, 
     ""FooArray"": [ 
      { 
       ""F1"": null, 
       ""F2"": null, 
       ""F3"": null 
      } 
     ] 
    }, 
    ""Bar"": null 
}"; 

JToken token = JsonHelper.RemoveEmptyChildren(JToken.Parse(json)); 
Console.WriteLine(token.ToString(Formatting.Indented)); 

Çıktı:

{ 
    "Foo": { 
    "P2": "hello world", 
    "P4": { 
     "P1": 1 
    }, 
    "FooArray": [ 
     {} 
    ] 
    } 
} 

Fiddle: https://dotnetfiddle.net/wzEOie

Bildirim, tüm boş değerler kaldırdıktan sonra FooArray boş bir nesne olacak , istemeyebilirsin. (Ve eğer bu nesne kaldırılmışsa, o zaman da isteyemeyeceğiniz boş bir FooArray olacaktır.) Eğer yardımcı yöntemini kaldırma işleminde daha agresif hale getirmek istiyorsanız, IsEmpty işlevini şu şekilde değiştirebilirsiniz:

yerine o değişiklikle
public static bool IsEmpty(JToken token) 
    { 
     return (token.Type == JTokenType.Null) || 
       (token.Type == JTokenType.Array && !token.HasValues) || 
       (token.Type == JTokenType.Object && !token.HasValues); 
    } 

, çıktı artık şöyle görünecektir:

{ 
    "Foo": { 
    "P2": "hello world", 
    "P4": { 
     "P1": 1 
    } 
    } 
} 

Fiddle: https://dotnetfiddle.net/ZdYogJ

+0

Teşekkürler! Soruyu gönderdikten hemen sonra neredeyse benzer bir algoritma ile geldim ama cevabınız hala geçerli :) – PoweredByOrange

+0

Sorun değil; yardımcı olduğuma sevindim. –

+0

Bunu başarmaya çalışırken sıkışmıştım, katkılarınız için teşekkürler, işe yarıyor! –

2

Brian'ın cevabı çalışır. Ayrıca, başka birinin ilgilenmesi durumunda, soruyu gönderdikten kısa bir süre sonra bunu yapmanın başka bir (ama yine de özyinelemeli) yolunu buldum.

private void RemoveNullNodes(JToken root) 
{ 
    if (root is JValue) 
    { 
     if (((JValue)root).Value == null) 
     { 
      ((JValue)root).Parent.Remove(); 
     } 
    } 
    else if (root is JArray) 
    { 
     ((JArray)root).ToList().ForEach(n => RemoveNullNodes(n)); 
     if (!(((JArray)root)).HasValues) 
     { 
      root.Parent.Remove(); 
     } 
    } 
    else if (root is JProperty) 
    { 
     RemoveNullNodes(((JProperty)root).Value); 
    } 
    else 
    { 
     var children = ((JObject)root).Properties().ToList(); 
     children.ForEach(n => RemoveNullNodes(n)); 

     if (!((JObject)root).HasValues) 
     { 
      if (((JObject)root).Parent is JArray) 
      { 
       ((JArray)root.Parent).Where(x => !x.HasValues).ToList().ForEach(n => n.Remove()); 
      } 
      else 
      { 
       var propertyParent = ((JObject)root).Parent; 
       while (!(propertyParent is JProperty)) 
       { 
        propertyParent = propertyParent.Parent; 
       } 
       propertyParent.Remove(); 
      } 
     } 
    } 
} 
2

Sen NullValueHandler.Ignore olan NullValueHandler set ile JsonSerializer belirterek başlamak oluşturulmasını boş belirteçleri önleyebilir. Bu JObject.FromObject'a, https://stackoverflow.com/a/29259032/263139'a bağlandığınız soruya verilen bir yanıtta görüldüğü gibi bir parametre olarak iletilir.