注意:如果您对此帖有更好的标题,请在评论中发帖。谢谢!
我正在使用一个返回json的api,它看起来像下面的代码片段。我对json非常熟悉,但我从未见过这样的结构。
resultFieldList fieldNames是固定的(下面有4个,但大约有20个)。 values数组是可变的,但每个fieldName的长度相同。
我在想我应该计算一个非空字段(OrderNumber),然后遍历每个fieldName,但这似乎效率低下。我想知道是否有更好的方法。这就是我获得记录数的方式:
string result = await response.Content.ReadAsStringAsync();
JObject m_json = (JObject)JsonConvert.DeserializeObject(result);
int m_count = m_json["resultFieldList"][3]["values"].Count();
这是json片段。
{
"collectionName": "Transactions",
"recordCount": 0,
"skippedRecordCount": 0,
"resultFieldList":
[{
"fieldName": "SaleChannel",
"analyticsDataType": "STRING",
"values": ["Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online", "Online"]
},
{
"fieldName": "Quantity",
"analyticsDataType": "INTEGER",
"values": [1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1, 3]
},
{
"fieldName": "Amount",
"analyticsDataType": "CURRENCY",
"values": ["25.00", "14.00", "14.00", "50.00", "14.00", "50.00", "14.00", "25.00", "18.00", "50.00", "36.00", "25.00", "50.00", "25.00", "14.00", "25.00", "50.00", "50.00", "25.00", "75.00"]
},
{
"fieldName": "OrderNumber",
"analyticsDataType": "STRING",
"values": ["60937129", "60937129", "53221966", "14599547", "14599547", "10478305", "10478305", "95344699", "95344699", "83413371", "65720270", "43458148", "52500933", "32742144", "32742144", "89850688", "61514108", "11080559", "90497730", "22838522"]
}]
}
准确的问题是是否可以创建一个新的数组或对象,其中每个值的索引被组合成给定此结构的新对象。例如,index [0]的值是" Online",1," 25.00"," 60937129"。所以它可能是一个新数组或一个全新的json对象。如果是这样,我将如何创建一个或另一个?输出将是这样的:
[ { "Online",1,"25.00","60937129" },{...} ]
或者
{"results": [ { "SaleChannel": "Online" , "Quantity": 1, "Amount": "25.00", "OrderNumber": "60937129" } , {...} ]
ANSWER
使用@ JLRishe的答案我能够解析和使用用例数据 - 将api数据插入数据仓库。
答案 0 :(得分:1)
修改:我相信在回答结束时我已经解决了你问题的要点。
您可能最好定义一个表示此结构的类型。由于values
数组的内容具有不同的类型,因此您无法真正对它们进行假设,并且可能最安全地将它们视为object
s:
public class MyClass
{
public string collectionName { get; set; }
public int recordCount { get; set; }
public int skippedRecordCount { get; set; }
public ResultField[] resultFieldList { get; set; }
}
public class ResultField
{
public string fieldName { get; set; }
public string analyticsDataType { get; set; }
public object[] values { get; set; }
}
然后解析JSON只是一个问题:
string result = await response.Content.ReadAsStringAsync();
MyClass obj = JsonConvert.DeserializeObject<MyClass>(result);
实际使用数据时,您需要查看analyticsDataType
中每个相应ResultField
的值,并相应地转换values
属性的内容。
或者,如果您不太关心将values
视为原始类型,则可以将它们全部视为字符串,这将需要更少的类型检查。其他一切都会保持不变:
public string[] values { get; set; }
编辑现在你已经澄清了这个问题了,似乎这主要是关于将数据整理成更好的消费方式。
如果resultFieldList
之外没有任何内容指示每个value
数组中的值的数量,那么您基本上需要随意选择一个来获取计数:
int valueCount = obj.resultFieldList[0].values.Length;
然后,一旦你有了,你可以将这些值组合在一起:
// assuming OrderItem is a class you've defined with the needed
// properties for one entry in an order
IEnumerable<OrderItem> items = Enumerable
.Range(0, valueCount)
.Select(i => new OrderItem {
SaleChannel = Convert.ToString(obj.resultFieldList[0].values[i]),
Quantity = Convert.ToInt32(obj.resultFieldList[1].values[i]),
Amount = Convert.ToDecimal(obj.resultFieldList[2].values[i]),
// etc...
});
答案 1 :(得分:0)
使用Newtonsoft.Json并执行以下操作:
1)定义你的课程:
public class SomeObject
{
public List<DynamicProperty> resultFieldList { get; set; }
}
public class DynamicProperty
{
public string fieldName { get; set; }
public string analyticsDataType { get; set; }
public List<object> values { get; set; }
}
2)反序列化你的JSON:
var obj = JsonConvert.DeserializeObject<SomeObject>(json);
var t = obj.resultFieldList[3].values.Count();
如果您有任何疑问,请与我们联系。我使用你的JSON进行了测试,答案是20.此外,你可以使用Linq进行更复杂的分析。
编辑:基于正在扩展的问题。
3)创建一个Order类:
public class Order
{
public string SaleChannel { get; set; }
public int Quantity { get; set; }
public Decimal Amount { get; set; }
public string OrderNumber { get; set; }
}
4)生成基于json的可枚举和序列化:
var jsonValue = JsonConvert.SerializeObject(Enumerable
.Range(0, obj.resultFieldList.Max(x => x.values.Count))
.Select(i => new Order()
{
SaleChannel = obj.resultFieldList.FirstOrDefault(x => x.fieldName == nameof(Order.SaleChannel))?.values[i].ToString(),
Quantity = Convert.ToInt32(obj.resultFieldList.FirstOrDefault(x => x.fieldName == nameof(Order.Quantity))?.values[i].ToString()),
Amount = Convert.ToDecimal(obj.resultFieldList.FirstOrDefault(x => x.fieldName == nameof(Order.Amount))?.values[i].ToString()),
OrderNumber = obj.resultFieldList.FirstOrDefault(x => x.fieldName == nameof(Order.OrderNumber))?.values[i].ToString()
}));
〜干杯