使用C#解析复杂JSON

我是JSON的新手,我有一些JSON,我试图用C#解析。

我试过用类来表示数据,但我的属性的名称是基于时间的,所以我必须硬编码我的数据合同。 我已经尝试过JSON.NET和LINQ来对数据进行排序,但由于奇怪的对象/属性而不断获取空值。

我再次对JSON很陌生,所以我确信有一个简单的解决方法,我只是不确定如何正确地提出问题。 谢谢您的帮助。

下面是我正在努力解析的一小部分JSON示例。 再次感谢。

{ "Meta Data": { "1. Information": "Intraday (1min) prices and volumes", "2. Symbol": "MU", "3. Last Refreshed": "2017-05-30 16:00:00", "4. Interval": "1min", "5. Output Size": "Full size", "6. Time Zone": "US/Eastern" }, "Time Series (1min)": { "2017-05-30 16:00:00": { "1. open": "30.7200", "2. high": "30.7300", "3. low": "30.7000", "4. close": "30.7000", "5. volume": "1390302" }, "2017-05-30 15:59:00": { "1. open": "30.7750", "2. high": "30.7800", "3. low": "30.7200", "4. close": "30.7250", "5. volume": "380134" } } } 

请注意, "Time Series"属性以1分钟,5分钟,15分钟,30分钟,60分钟的间隔,即"Time Series (##min)"为各种##min

您可以使用此类来反序列化该特定的 Json文件,这里我假设Time Series (1min)内的两个对象在每个json文件中都具有相同的名称。 但考虑到它们是日期,我很确定每次下载json时会有所不同。

只是为了让您了解使用Newtonsoft Json属性可以做些什么:

 public class MetaData { [JsonProperty("1. Information")] public string Information { get; set; } [JsonProperty("2. Symbol")] public string Symbol { get; set; } [JsonProperty("3. Last Refreshed")] public string LastRefreshed { get; set; } [JsonProperty("4. Interval")] public string Interval { get; set; } [JsonProperty("5. Output Size")] public string OutputSize { get; set; } [JsonProperty("6. Time Zone")] public string TimeZone { get; set; } } public class T1 { [JsonProperty("1. Information")] public string Open { get; set; } [JsonProperty("2. high")] public string High { get; set; } [JsonProperty("3. low")] public string Low { get; set; } [JsonProperty("4. close")] public string Close { get; set; } [JsonProperty("5. volume")] public string Volume { get; set; } } public class T2 { [JsonProperty("1. Information")] public string Open { get; set; } [JsonProperty("2. high")] public string High { get; set; } [JsonProperty("3. low")] public string Low { get; set; } [JsonProperty("4. close")] public string Close { get; set; } [JsonProperty("5. volume")] public string Volume { get; set; } } public class TimeSeries { [JsonProperty("2017-05-30 16:00:00")] public T1 T1 { get; set; } [JsonProperty("2017-05-30 15:59:00")] public T2 T2 { get; set; } } public class RootObject { [JsonProperty("Meta Data")] public MetaData MetaData { get; set; } [JsonProperty("Time Series (1min)")] public TimeSeries TimeSeries { get; set; } } 

然后,当您反序列化时:

 var deserializedObject = JsonConvert.DeserializeObject( File.ReadAllText("exampleFile.json")); 

如果你能告诉我们更多关于你json文件的信息,我们可以帮助你。

您可以尝试使用JsonCovert,如下所示

 string json = @"{ 'Meta Data': { '1. Information': 'Intraday (1min) prices and volumes', '2. Symbol': 'MU', '3. Last Refreshed': '2017-05-30 16:00:00', '4. Interval': '1min', '5. Output Size': 'Full size', '6. Time Zone': 'US/Eastern' }, 'Time Series (1min)': { '2017-05-30 16:00:00': { '1. open': '30.7200', '2. high': '30.7300', '3. low': '30.7000', '4. close': '30.7000', '5. volume': '1390302' }, '2017-05-30 15:59:00': { '1. open': '30.7750', '2. high': '30.7800', '3. low': '30.7200', '4. close': '30.7250', '5. volume': '380134' } } }"; var jsonConvertedData = JsonConvert.DeserializeObject(json); 

这将解析json字符串到json对象。

您希望将JSON系列反序列化为某种c#类型,但由于JSON对象同时具有固定和可变属性名称,因此不明显如何这样做,因为它们都不对应于有效的c#标识符。 特别:

  • 您的根对象具有属性"Meta Data" ,该属性对应于具有字符串键/值对集合的JSON对象。 根据此问题的答案,您可以将其绑定到字典属性:

     [JsonProperty("Meta Data")] public Dictionary MetaData { get; set; } 
  • 此外,您的根对象具有一组任意属性,其名称类似于“时间序列(## min)”,用于各种##min ,具有对应于Dictionary>固定模式 。 因为这些属性具有固定的模式,所以不能像使用已知和未知字段反序列化json中那样使用[JsonExtensionData] 。 相反,您可以使用如何使用动态(数字)键名称反序列 TypedExtensionDataConverter 对象的转换器TypedExtensionDataConverter ? 要反序列化根对象,使时间序列属性如下:

     [JsonTypedExtensionData] public Dictionary>> TimeSeries { get; set; } 

因此,您可以按如下方式设计根对象:

 [JsonConverter(typeof(TypedExtensionDataConverter))] public class RootObject { public RootObject() { // Ensure dictionaries are allocated. this.MetaData = new Dictionary(); this.TimeSeries = new Dictionary>>(); } [JsonProperty("Meta Data")] public Dictionary MetaData { get; set; } [JsonTypedExtensionData] public Dictionary>> TimeSeries { get; set; } } 

使用TypedExtensionDataConverter从此答案逐字复制。

样品小提琴 。

请注意,如果每个时间序列时间的属性名称"1. open""2. high"等等都是固定的,则可以使用类似于@ FrancescoB的答案中的T1的预定义类型而不是Dictionary

 [JsonConverter(typeof(TypedExtensionDataConverter))] public class RootObject { public RootObject() { // Ensure dictionaries are allocated. this.MetaData = new Dictionary(); this.TimeSeries = new Dictionary>(); } [JsonProperty("Meta Data")] public Dictionary MetaData { get; set; } [JsonTypedExtensionData] public Dictionary> TimeSeries { get; set; } } public class TimeSeriesData { [JsonProperty("1. open")] public decimal Open { get; set; } [JsonProperty("2. high")] public decimal High { get; set; } [JsonProperty("3. low")] public decimal Low { get; set; } [JsonProperty("4. close")] public decimal Close { get; set; } [JsonProperty("5. volume")] public decimal Volume { get; set; } } 

样品小提琴#2 。

要实现在TimeSeries为两个属性创建动态名称的效果,可以手动解析json树(使用Newtonsoft Json库):

反序列化域:

 public class MetaData { public string Information { get; set; } public string Symbol { get; set; } public DateTime LastRefreshed { get; set; } public string Interval { get; set; } public string OutputSize { get; set; } public string TimeZone { get; set; } } public class TimeSeriesInfos { public double Open { get; set; } public double High { get; set; } public double Low { get; set; } public double Close { get; set; } public double Volume { get; set; } } public class TimeSeries { public TimeSeriesInfos T1 { get; set; } public TimeSeriesInfos T2 { get; set; } } public class RootObject { public MetaData MetaData { get; set; } public TimeSeries TimeSeries { get; set; } } 

然后像这样反序列化:

 var jsonObjectTree = JsonConvert.DeserializeObject( File.ReadAllText("exampleFile.json")); const string metaDataName = "Meta Data"; const string timeSeriesName = "Time Series (1min)"; const string openName = "1. open"; const string highName = "2. high"; const string lowName = "3. low"; const string closeName = "4. close"; const string volumeName = "5. volume"; // You can obtain dynamically those two properties string t1Name = "2017-05-30 16:00:00"; string t2Name = "2017-05-30 15:59:00"; var deserializedObject = new RootObject() { MetaData = new MetaData() { Information = jsonObjectTree[metaDataName]["1. Information"].Value(), Symbol = jsonObjectTree[metaDataName]["2. Symbol"].Value(), LastRefreshed = DateTime.ParseExact(jsonObjectTree[metaDataName]["3. Last Refreshed"].Value(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), Interval = jsonObjectTree[metaDataName]["4. Interval"].Value(), OutputSize = jsonObjectTree[metaDataName]["5. Output Size"].Value(), TimeZone = jsonObjectTree[metaDataName]["6. Time Zone"].Value() }, TimeSeries = new TimeSeries() { T1 = new TimeSeriesInfos() { Open = jsonObjectTree[timeSeriesName][t1Name][openName].Value(), High = jsonObjectTree[timeSeriesName][t1Name][highName].Value(), Low = jsonObjectTree[timeSeriesName][t1Name][lowName].Value(), Close = jsonObjectTree[timeSeriesName][t1Name][closeName].Value(), Volume = jsonObjectTree[timeSeriesName][t1Name][volumeName].Value() }, T2 = new TimeSeriesInfos() { Open = jsonObjectTree[timeSeriesName][t2Name][openName].Value(), High = jsonObjectTree[timeSeriesName][t2Name][highName].Value(), Low = jsonObjectTree[timeSeriesName][t2Name][lowName].Value(), Close = jsonObjectTree[timeSeriesName][t2Name][closeName].Value(), Volume = jsonObjectTree[timeSeriesName][t2Name][volumeName].Value() } } };