我有一个JObject用作调用RESTful Web服务的 模板 。这JObject是通过解析器创建的,由于它被用作告诉用户端点模式的模板,因此我不得不想出一种保留所有属性的方法,这就是为什么将其默认值设置为的原因null。作为示例,这是对象最初的外观:
JObject
null
{ "Foo":{ "P1":null, "P2":null, "P3":null, "P4":{ "P1":null, "P2":null, "P3":null, }, "FooArray":[ { "F1":null, "F2":null, "F3":null, } ] }, "Bar":null }
然后,用户可以根据需要填写各个字段,例如Foo.P2和Foo.P4.P1:
Foo.P2
Foo.P4.P1
{ "Foo":{ "P1":null, "P2":"hello world", "P3":null, "P4":{ "P1":1, "P2":null, "P3":null, }, "FooArray":[ { "F1":null, "F2":null, "F3":null, } ] }, "Bar":null }
表示他们只关心这两个领域。现在,我想将此模板(JObject)序列化回一个JSON字符串,但只希望显示填充的那些字段。所以我尝试了这个:
string json = JsonConvert.SerializeObject(template, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
不幸的是,这没有用。我遇到了这个问题,并意识到null对象中的值是实际JToken类型,而不是真正的anull,这很有意义。但是,在这种非常特殊的情况下,我需要能够摆脱这些“未使用”的字段。我尝试过手动遍历节点并删除它们,但这也不起作用。注意,我使用的唯一托管类型是JObject; 我没有将对象转换为对象或在其上定义属性的模型,因为此“模板”在运行时已解析。我只是想知道是否有人遇到过这样的问题并且有任何见解。任何帮助是极大的赞赏!
JToken
您可以使用一种类似于下面的递归帮助器方法来在序列化之前null从JToken层次结构中删除值。
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); } }
演示:
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));
输出:
{ "Foo": { "P2": "hello world", "P4": { "P1": 1 }, "FooArray": [ {} ] } }
小提琴:https : //dotnetfiddle.net/wzEOie
请注意,删除所有空值后,您可能会在中有一个空对象FooArray,您可能不需要。(如果删除了该对象,则FooArray可能会有一个空值,您可能也不想这样做。)如果要使helper方法在删除它时更加主动,则可以将IsEmpty函数更改为:
FooArray
public static bool IsEmpty(JToken token) { return (token.Type == JTokenType.Null) || (token.Type == JTokenType.Array && !token.HasValues) || (token.Type == JTokenType.Object && !token.HasValues); }
进行适当的更改后,您的输出将如下所示:
{ "Foo": { "P2": "hello world", "P4": { "P1": 1 } } }
小提琴:https://dotnetfiddle.net/ZdYogJ