遍历从 JSON 文件生成的动态对象的问题
Issues Iterating through a dynamic object generated from a JSON file
我有一个 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
}
}
}
}
我遇到的问题是在只有 1 个条目的情况下迭代第三级时。
根据 JSON 的性质,如果通知类型有多个条目,那么在我的 notifications.Value
中将有另一个集合列表。在这种情况下,我的代码就像一个魅力。
但是,如果通知只有 1 个条目,notification.value
实际上包含单个条目中所有值的 KeyValuePair
列表。所以第 3 级迭代不起作用。它实际上是在尝试迭代该点的值。
很遗憾,我正在使用的 json 无法修改,这是我将要接收的格式。
我希望这能准确解释我遇到的问题。我知道问题出在哪里,只是完全不确定如何解决它。
首先,您可以考虑切换到 JavaScriptSerializer
使用的 json.net. If you do, you could deserialize directly to a Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>
using SingleOrArrayConverter<Dictionary<string, string>>
from How to handle both a single item and an array for the same property using JSON.net. This also avoids the 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://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()
));
现在您已经有了完全类型化的字典层次结构,您应该可以继续创建最终模型了。
我有一个 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
}
}
}
}
我遇到的问题是在只有 1 个条目的情况下迭代第三级时。
根据 JSON 的性质,如果通知类型有多个条目,那么在我的 notifications.Value
中将有另一个集合列表。在这种情况下,我的代码就像一个魅力。
但是,如果通知只有 1 个条目,notification.value
实际上包含单个条目中所有值的 KeyValuePair
列表。所以第 3 级迭代不起作用。它实际上是在尝试迭代该点的值。
很遗憾,我正在使用的 json 无法修改,这是我将要接收的格式。
我希望这能准确解释我遇到的问题。我知道问题出在哪里,只是完全不确定如何解决它。
首先,您可以考虑切换到 JavaScriptSerializer
使用的 json.net. If you do, you could deserialize directly to a Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>
using SingleOrArrayConverter<Dictionary<string, string>>
from How to handle both a single item and an array for the same property using JSON.net. This also avoids the 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://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()
));
现在您已经有了完全类型化的字典层次结构,您应该可以继续创建最终模型了。