我正在通过API从我们的调查提供商中提取调查回复。我没有为此使用类来反序列化,它只是键/值对。
我正在从文件中读取一系列响应。每个响应都包含许多我们称之为"响应项",如下所示:
[
{
"response_id":"1234",
"hRz5aMmGPf": null,
"6UnnAZSEBT": null,
"nGS1cyvLwK": "Red"
},
{
"response_id":"1235",
"hRz5aMmGPf": "John Smith",
"6UnnAZSEBT": null,
"nGS1cyvLwK": "Blue"
},
{
"response_id":"1236",
"hRz5aMmGPf": "Jane Doe",
"6UnnAZSEBT": "Yes",
"nGS1cyvLwK": null
}
]
出于本练习的目的,我从文件中读取 JSON,如下所示:
List<JToken> responseobjs = new List<JToken>();
JObject o = JObject.Parse(fcontents);
responseobjs.AddRange(o["results"].Children())
根据示例数据,源数据中有很多空值,我想以最快的方式消除这些空值。我已经阅读了"NullValueHandling",但这似乎仅适用于我反序列化为类/对象的情况,这在提要返回不同的字段 ID 时是不可能的。
我可以拿上面的 Children() 但跳过空值吗?
现在,我正在迭代响应,然后迭代响应项以删除空值,并且转换需要很长时间。
foreach (JToken obj in responseobjs)
{
foreach (JProperty rprop in obj.Where(x=> x.HasValues==true).ToList())
{
if (rprop.Value.ToString().Trim() == "")
continue;
..Continue parsing here...
}
}
如果已经解析了 JSON,则删除 null 值的唯一方法是像您已经做的那样单独检查每个属性。 另一种方法是在读取 JSON 时删除 null,这样以后就不必筛选它们。 Json.Net 不提供现成的此功能,但可以编写一个直接与 JsonReader
一起使用的帮助程序方法,以生成排除 null 值的JToken
层次结构:
static JToken DeserializeExcludingNulls(string json)
{
using (JsonTextReader reader = new JsonTextReader(new StringReader(json)))
{
return DeserializeExcludingNulls(reader);
}
}
static JToken DeserializeExcludingNulls(JsonReader reader)
{
if (reader.TokenType == JsonToken.None)
{
reader.Read();
}
if (reader.TokenType == JsonToken.StartArray)
{
reader.Read();
JArray array = new JArray();
while (reader.TokenType != JsonToken.EndArray)
{
JToken token = DeserializeExcludingNulls(reader);
if (!IsEmpty(token))
{
array.Add(token);
}
reader.Read();
}
return array;
}
if (reader.TokenType == JsonToken.StartObject)
{
reader.Read();
JObject obj = new JObject();
while (reader.TokenType != JsonToken.EndObject)
{
string propName = (string)reader.Value;
reader.Read();
JToken token = DeserializeExcludingNulls(reader);
if (!IsEmpty(token))
{
obj.Add(propName, token);
}
reader.Read();
}
return obj;
}
return new JValue(reader.Value);
}
static bool IsEmpty(JToken token)
{
return (token.Type == JTokenType.Null);
}
这是一个演示:
string json = @"
[
{
""response_id"":""1234"",
""hRz5aMmGPf"": null,
""6UnnAZSEBT"": null,
""nGS1cyvLwK"": ""Red"",
},
{
""response_id"":""1235"",
""hRz5aMmGPf"": ""John Smith"",
""6UnnAZSEBT"": null,
""nGS1cyvLwK"": ""Blue""
},
{
""response_id"":""1236"",
""hRz5aMmGPf"": ""Jane Doe"",
""6UnnAZSEBT"": ""Yes"",
""nGS1cyvLwK"": null
}
]";
JArray array = (JArray)DeserializeExcludingNulls(json);
foreach (JObject obj in array)
{
foreach (JProperty prop in obj.Properties())
{
Console.WriteLine(prop.Name + ": " + prop.Value);
}
Console.WriteLine();
}
输出:
response_id: 1234
nGS1cyvLwK: Red
response_id: 1235
hRz5aMmGPf: John Smith
nGS1cyvLwK: Blue
response_id: 1236
hRz5aMmGPf: Jane Doe
6UnnAZSEBT: Yes
如果还想排除空字符串,可以相应地更改IsEmpty
方法:
static bool IsEmpty(JToken token)
{
return (token.Type == JTokenType.Null) ||
(token.Type == JTokenType.String && token.ToString().Trim() == "");
}
很长,但我用它来过滤掉 jsondiffpatch.net diff() 中的空值,所以我的单元测试通过(我的模型不序列化空值,但原始 json 可能包含空值)。
public static class JTokenExtensions
{
public static JToken RemoveNulls(this JToken node)
{
var children = node.Children().ToArray();
var nonTrivialChildren = children.Select(c => RemoveNulls(c)).Any(v => v != null);
if (nonTrivialChildren)
return node;
// once trivial children are removed, values will be different
var values = node.Values().ToArray();
var nonTrivialValues = values.Any(v => v != null);
if (nonTrivialValues)
return node;
// the parent needs to be removed instead
switch (node.Type)
{
case JTokenType.Boolean:
case JTokenType.Date:
case JTokenType.Float:
case JTokenType.Integer:
case JTokenType.String:
return node;
case JTokenType.Array:
case JTokenType.Object:
return null;
case JTokenType.Null:
break;
}
node.Remove();
return null;
}
}