我有一个json文件(为了这个问题)我简化了:
{
"servername": {
"goodvolumes": [
{
"Name": "vol1",
"State": "online",
"Size": "12.0 TB"
},
{
"Name": "vol2",
"State": "online",
"Size": "10.0 TB"
}
],
"BadVolumes": {
"Name": "badVol",
"State": "offline",
"TotalSize": "120GB"
}
}
}
当读入我的C#时,我有一个System.Collections.Generic.Dictionary<string,object>
类型的数据对象。
然后我遍历对象并创建一个模型对象,我将要传递给我的视图。
这给我带来了困难。这是我如何迭代json的一个例子。
//top level of my JSON - the serverName
foreach(serverName in jsonData)
{
//record the serverName
//second level of my JSON - the notification name
foreach(notification in serverName.Value)
{
//record the notification name
//3rd Level of my JSON - iterating the entries
foreach(entry in notification.Value)
{
//Iterating all the values in an entry
foreach(entryValue in entry)
{
//record values in each entry
}
}
}
}
我遇到的问题是,如果只有一个条目,则迭代第三级。
根据JSON的性质,如果通知类型有多个条目,那么在我的notifications.Value
内部将会有另一个集合列表。在这种情况下,我的代码就像一个魅力。
但是,如果通知只有一个条目,notification.value
实际上包含单个条目中所有值的KeyValuePair
列表。所以第三级迭代不起作用。它实际上是试图在那时迭代值。
不幸的是,我正在使用的json无法修改,这是我将要接收它的格式。
我希望这能准确地解释我所遇到的问题。我知道问题出在哪里,我根本不确定如何绕过它。
答案 0 :(得分:2)
首先,您可以考虑切换到json.net。如果您这样做,可以使用How to handle both a single item and an array for the same property using JSON.net中的Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>
直接反序列化为SingleOrArrayConverter<Dictionary<string, string>>
。这也避免了JavaScriptSerializer
使用的proprietary date format。
使用JavaScriptSerializer
,您需要了解它如何反序列化任意JSON数据的一些细节。具体来说,它将JSON对象反序列化为IDictionary<string, object>
,将JSON数组反序列为某种非词典,非string
IEnumerable
。以下扩展方法实现了这些检查:
public static class JavaScriptSerializerObjectExtensions
{
public static bool IsJsonArray(this object obj)
{
if (obj is string || obj.IsJsonObject())
return false;
return obj is IEnumerable;
}
public static IEnumerable<object> AsJsonArray(this object obj)
{
if (obj is string || obj.IsJsonObject())
return null;
return (obj as IEnumerable).Cast<object>();
}
public static bool IsJsonObject(this object obj)
{
return obj is IDictionary<string, object>;
}
public static IDictionary<string, object> AsJsonObject(this object obj)
{
return obj as IDictionary<string, object>;
}
/// <summary>
/// If the incoming object corresponds to a JSON array, return it. Otherwise wrap it in an array.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static IEnumerable<object> ToJsonArray(this object obj)
{
if (obj.IsJsonArray())
return obj.AsJsonArray();
return new[] { obj };
}
public static string JsonPrimitiveToString(this object obj, bool isoDateFormat = true)
{
if (obj == null)
return null; // Or return "null" if you prefer.
else if (obj is string)
return (string)obj;
else if (obj.IsJsonArray() || obj.IsJsonObject())
return new JavaScriptSerializer().Serialize(obj);
else if (isoDateFormat && obj is DateTime)
// Return in ISO 8601 format not idiosyncratic JavaScriptSerializer format
// https://stackoverflow.com/questions/17301229/deserialize-iso-8601-date-time-string-to-c-sharp-datetime
// https://msdn.microsoft.com/en-us/library/az4se3k1.aspx#Roundtrip
return ((DateTime)obj).ToString("o");
else
{
var s = new JavaScriptSerializer().Serialize(obj);
if (s.Length > 1 && s.StartsWith("\"", StringComparison.Ordinal) && s.EndsWith("\"", StringComparison.Ordinal))
s = s.Substring(1, s.Length - 2);
return s;
}
}
}
然后你可以按如下方式反序列化:
var jsonData = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(jsonString);
Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>> finalData;
// I could have just done var finalData = ... here. I declared finalData explicitly to makes its type explicit.
finalData =
jsonData.ToDictionary(
p1 => p1.Key,
p1 => p1.Value
.AsJsonObject()
.ToDictionary(
p2 => p2.Key,
p2 => (p2.Value.ToJsonArray().Select(a => a.AsJsonObject())).Select(o => o.ToDictionary(p3 => p3.Key, p3 => p3.Value.JsonPrimitiveToString())).ToList()
));
既然您拥有完全类型的词典层次结构,那么您应该能够继续创建最终模型。