【问题标题】:C#: Parsing a non-JSON array-only api response to a class object with x propertiesC#:解析对具有 x 属性的类对象的非 JSON 仅数组 api 响应
【发布时间】: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

之类的查询

【问题讨论】:

  • 带双引号的值是浮点数,不是字符串。
  • 您知道各个列的架构吗?即第一列是起始值,等等?另外,您使用什么进行 JSON 解析?是json.net吗?
  • @ole:感谢您的链接,但收到的字符串不符合 json 标准,因为没有“关键字”等。
  • @AlexanderS。 - 它是格式完美的 JSON。上传到jsonlint.com,没有错误。只是所有容器都是数组(值的有序序列)而不是对象(名称/值对的无序序列)。请参阅json.org 进行确认。

标签: c# arrays json api parsing


【解决方案1】:

API 响应完全有效JSON;它是原始值的锯齿状二维数组,其中列具有Public Rest API for Binance: Kline/Candlestick data 中定义的特定含义。因此,可以使用 对其进行解析和反序列化,例如作为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&lt;BinanceKlineData&gt; 反序列化为List&lt;BinanceKlineData&gt;

首先,使用列的文档含义,您可以定义您的类型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&lt;T&gt;。它具有利用Order = N 元数据按列索引将行值映射到通用类型T 中的成员值的逻辑。

最后,您将能够将 JSON 反序列化为 List&lt;BinanceKlineData&gt;,如下所示:

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

【讨论】:

    猜你喜欢
    • 2020-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 2017-10-12
    • 2015-12-01
    相关资源
    最近更新 更多