C#:解析对具有 x 属性的类对象的非 JSON 仅数组 api 响应
Posted
技术标签:
【中文标题】C#:解析对具有 x 属性的类对象的非 JSON 仅数组 api 响应【英文标题】:C#: Parsing a non-JSON array-only api response to a class object with x properties 【发布时间】:2018-07-03 22:11:28 【问题描述】:我有来自一些 Rest API 的响应,它只返回一些数组,如下所示:
[
[123,"0.01","0.02","0.03","0.04","12345.00000",123456789,"300.000",4000,"123.000","456.000","0"],
[456,"0.04","0.03","0.02","0.01","54321.00000",987654321,"500.000",4000,"123.000","456.000","1"],
[789,"0.05","0.06","0.07","0.08","12345.00000",123456789,"700.000",8000,"456.000","123.000","0"]
]
在这个例子中,数据集的数量是 3,但数量总是不同的,也可能是 100+。
我想把这个读出到一个类对象中,根据响应中显示的每种类型的值,它有 12 个数组:
public class foo
...
public int[] firstParam;
public string[] secondParam;
public string[] thirdParam;
...
例如,firstParam
应包含 123,456,789
; secondParam
应该包含"0.01","0.04","0.05"
等等。
列的架构已知并记录在Public Rest API for Binance: Kline/Candlestick data. 中。例如https://api.binance.com/api/v1/klines?symbol=XVGBTC&interval=1h
之类的查询【问题讨论】:
试试这个链接:***.com/a/10432672/4180382 带双引号的值是浮点数,不是字符串。 您知道各个列的架构吗?即第一列是起始值,等等?另外,您使用什么进行 JSON 解析?是json.net吗? @ole:感谢您的链接,但收到的字符串不符合 json 标准,因为没有“关键字”等。 @AlexanderS。 - 它是格式完美的 JSON。上传到jsonlint.com,没有错误。只是所有容器都是数组(值的有序序列)而不是对象(名称/值对的无序序列)。请参阅json.org 进行确认。 【参考方案1】:API 响应完全有效JSON;它是原始值的锯齿状二维数组,其中列具有Public Rest API for Binance: Kline/Candlestick data 中定义的特定含义。因此,可以使用json.net 对其进行解析和反序列化,例如作为object [][]
:
var arrays = JsonConvert.DeserializeObject<object [][]>(jsonString);
(工作示例.Net fiddle #1。)
但是,与其将 JSON 反序列化为锯齿状二维对象数组或(如您在问题中建议的那样)具有与列值对应的数组属性的单个根对象,我建议您设计一个类 BinanceKlineData
表示这些特定列的单行值,然后使用来自How to deserialize an array of values with a fixed schema to a strongly typed data class? 的custom JsonConverter
ObjectToArrayConverter<BinanceKlineData>
反序列化为List<BinanceKlineData>
。
首先,使用列的文档含义,您可以定义您的类型BinanceKlineData
,如下所示:
public class BinanceKlineData
[JsonProperty(Order = 1)]
public long OpenTime get; set;
[JsonProperty(Order = 2)]
public decimal Open get; set; // Or string, if you prefer
[JsonProperty(Order = 3)]
public decimal High get; set; // Or string, if you prefer
[JsonProperty(Order = 4)]
public decimal Low get; set; // Or string, if you prefer
[JsonProperty(Order = 5)]
public decimal Close get; set; // Or string, if you prefer
[JsonProperty(Order = 6)]
public decimal Volume get; set; // Or string, if you prefer
[JsonProperty(Order = 7)]
public long CloseTime get; set;
[JsonProperty(Order = 8)]
public decimal QuoteAssetVolume get; set; // Or string, if you prefer
[JsonProperty(Order = 9)]
public long NumberOfTrades get; set; // Should this be an long or a decimal?
[JsonProperty(Order = 10)]
public decimal TakerBuyBaseAssetVolume get; set;
[JsonProperty(Order = 11)]
public decimal TakerBuyQuoteAssetVolume get; set;
// public string Ignore get; set;
请注意,我已使用 [JsonProperty(Order = N)]
注释属性。此顺序对应于 Rest API 中列的顺序,将用于通知 Json.NET 如何通过列索引将列映射到属性。另请注意,我将数字列建模为decimal
,尽管它们在 JSON 中显示为字符串。如果您更喜欢文字反序列化,可以使用 string
。
接下来,从this answer 中获取通用ObjectToArrayConverter<T>
。它具有利用Order = N
元数据按列索引将行值映射到通用类型T
中的成员值的逻辑。
最后,您将能够将 JSON 反序列化为 List<BinanceKlineData>
,如下所示:
var settings = new JsonSerializerSettings
Converters = new ObjectToArrayConverter<BinanceKlineData>() ,
;
var root = JsonConvert.DeserializeObject<List<BinanceKlineData>>(jsonString, settings);
样本工作.Net fiddle #2。
或者,如果您愿意,可以将转换器直接应用到BinanceKlineData
,如下所示:
[JsonConverter(typeof(ObjectToArrayConverter<BinanceKlineData>))]
public class BinanceKlineData
// Remainder as before
当转换器直接应用于类型时,不再需要通过JsonSerializerSettings.Converters
传递它。
示例fiddle #3。
【讨论】:
@AlexanderS。 - 不客气。如果问题得到解答,请mark it as such。【参考方案2】:根据响应的确切格式,您可能可以执行以下操作:
var s = "[[123,\"0.01\",\"0.02\",\"0.03\",\"0.04\",\"12345.00000\",123456789,\"300.000\",4000,\"123.000\",\"456.000\",\"0\"],[456,\"0.04\",\"0.03\",\"0.02\",\"0.01\",\"54321.00000\",987654321,\"500.000\",4000,\"123.000\",\"456.000\",\"1\"],[789,\"0.05\",\"0.06\",\"0.07\",\"0.08\",\"12345.00000\",123456789,\"700.000\",8000,\"456.000\",\"123.000\",\"0\"]]";
var lines = s.Split(new char[] '[', ']' , StringSplitOptions.RemoveEmptyEntries).Select(a => a.Split(new char[] ',' , StringSplitOptions.RemoveEmptyEntries).Select(b => b.TrimEnd('"').TrimStart('"')).ToArray()).Where(a => a.Any());
var c = lines.Count();
var foo = new foo
firstParam = new int[c],
secondParam = new string[c],
thirdParam = new string[c]
;
for (int i = 0; i < c; i++)
foo.firstParam[i] = Int32.Parse(lines.ElementAt(i)[0]);
foo.secondParam[i] = lines.ElementAt(i)[1];
foo.thirdParam[i] = lines.ElementAt(i)[2];
Console.WriteLine(string.Join(", ", foo.firstParam)); \\123, 456, 789
Console.WriteLine(string.Join(", ", foo.secondParam)); \\0.01, 0.04, 0.05
Console.WriteLine(string.Join(", ", foo.thirdParam)); \\0.02, 0.03, 0.06
【讨论】:
以上是关于C#:解析对具有 x 属性的类对象的非 JSON 仅数组 api 响应的主要内容,如果未能解决你的问题,请参考以下文章