我正在通过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'但这似乎只适用于我反序列化为类/对象的情况,这是由于Feed返回的不同字段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...
}
}
答案 0 :(得分:2)
如果您已经解析了JSON,那么删除空值的唯一方法就是像您现在一样单独检查每个属性。另一种方法是在读取JSON时删除空值,因此您不必在以后过滤它们。 Json.Net不提供开箱即用的功能,但是可以编写一个直接与JsonReader
一起工作的辅助方法来构建一个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() == "");
}
答案 1 :(得分:0)
感觉很冗长,但是我使用它来过滤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;
}
}