我正在制作一个需要解析JSON响应的程序。响应中的大多数数据都是无用的,但我需要用它做一些事情
- 能够从
rgInventory
部分检索对id
的搜索,然后获得相应的classid
- 获取具有此
classid
的对象的market_name
JSON响应(摘录,继续使用该格式):
{
"success":true,
"rgInventory":{
"1482735510":{
"id":"1482735510",
"classid":"469449975",
"instanceid":"0",
"amount":"1",
"pos":1
},
"1468698711":{
"id":"1468698711",
"classid":"619638799",
"instanceid":"0",
"amount":"1",
"pos":2
},
},
"rgCurrency":[
],
"rgDescriptions":{
"469449975_0":{
"appid":"730",
"classid":"469449975",
"instanceid":"0",
"icon_url":"fWFc82js0fmoRAP-qOIPu5THSWqfSmTELLqcUywGkijVjZYMUrsm1j-9xgEObwgfEh_nvjlWhNzZCveCDfIBj98xqodQ2CZknz5oM7bgZghmfzvDE61HY-Yy_QbpNis77893GtbmoLpffljq4tCXNLN9ZY0fSZPVCaWPZQ_5v0tshKIJK5KBqSjs2i73ejBdAx_EB8I",
"icon_url_large":"fWFc82js0fmoRAP-qOIPu5THSWqfSmTELLqcUywGkijVjZYMUrsm1j-9xgEObwgfEh_nvjlWhNzZCveCDfIBj98xqodQ2CZknz5oM7bgZghmfzvDE61HY-Yy_QbpNis77893a9u35bwDZ13vs9PPNOQpZoodGMOBD6PVMFr4uRgxg6dZepXdpCm72SrhM2wJXBD1ujVT-Ntzxu8",
"icon_drag_url":"",
"name":"SG 553 | Army Sheen",
"market_hash_name":"SG 553 | Army Sheen (Factory New)",
"market_name":"SG 553 | Army Sheen (Factory New)",
"name_color":"D2D2D2",
"background_color":"",
"type":"Consumer Grade Rifle",
"tradable":1,
"marketable":1,
"commodity":0,
"descriptions":[
{
"type":"html",
"value":"Exterior: Factory New"
},
{
"type":"html",
"value":"The Bank Collection",
"color":"9da1a9",
"app_data":{
"def_index":"65535",
"is_itemset_name":1
}
},
],
"actions":[
{
"name":"Inspect in Game...",
"link":"steam://rungame/730/76561202255233023/+csgo_econ_action_preview%20S%owner_steamid%A%assetid%D2486209296654018845"
}
],
"market_actions":[
{
"name":"Inspect in Game...",
"link":"steam://rungame/730/76561202255233023/+csgo_econ_action_preview%20M%listingid%A%assetid%D2486209296654018845"
}
],
"tags":[
{
"internal_name":"CSGO_Type_Rifle",
"name":"Rifle",
"category":"Type",
"category_name":"Type"
},
{
"internal_name":"weapon_sg556",
"name":"SG 553",
"category":"Weapon",
"category_name":"Weapon"
},
]
}
}
}
完整的JSON响应:http://steamcommunity.com/id/Mambocsgoshack/inventory/json/730/2/
我相信,因为库存中的每个项目(即469449975_0
到619638799_0
)的标识符都在不断变化,所以我必须将其反序列化为字典。
这是我迄今为止的代码:
namespace SteamTrade
{
public class CSGOInventory
{
public static CSGOInventory FetchInventory(string steamId)
{
WebClient client = new WebClient();
var url = "http://steamcommunity.com/profiles/" + steamId + "/inventory/json/730/2/";
string response = client.DownloadString(url);
Dictionary<string, Item> result = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, Item>>(response);
return new CSGOInventory(result);
}
public Item[] Items { get; set; }
public bool IsPrivate { get; private set; }
public bool IsGood { get; private set; }
protected CSGOInventory(Dictionary<string, Item> apiInventory)
{
for (int i = 0; i < apiInventory.Count; i++)
{
Items[i] = apiInventory.Values.ElementAt(i);
}
}
/*public Item GetItem(int id)
{
return (Items == null ? null : Items.FirstOrDefault(item => item.instanceid == id));
}
public List<Item> GetItemsByDefindex(int defindex)
{
return Items.Where(item => item.def_index == defindex).ToList();
}*/
public class Item
{
public string AppId = "730";
public string ContextId = "2";
[JsonProperty("instanceid")]
public string instanceid { get; set; }
[JsonProperty("market_name")]
public string market_name { get; set; }
[JsonProperty("def_index")]
public string def_index { get; set; }
}
protected class InventoryResult
{
public Item[] items { get; set; }
}
protected class InventoryResponse
{
public InventoryResult result;
}
}
}
我认为我将字典项添加到items数组中完全错误,但无法找到正确的解决方案。
然而,目前的错误是:
将值True转换为类型"SteamTrade.CSGOInventory+Item"时出错,路径"success",第1行,位置15。
我有点理解这意味着什么,但不知道如何解决它。我不认为我必须定义JSON在我的对象中返回的每个属性,但我很可能错了。不管怎样,由于JSON的格式从rgInventory
到rgDescriptions
部分都发生了变化,我不知道如何解决这个问题。有人能解释一下怎么做吗?
更新:
我从market_name检索instanceid的方法如下:
public string getInstanceIdFromMarketName(string name)
{
var classIdToId = inventory.rgInventory.ToLookup(pair => pair.Value.classid, pair => pair.Key);
var marketNameToId = inventory.rgDescriptions
.SelectMany(pair => classIdToId[pair.Value.classid].Select(id => new KeyValuePair<string, string>(pair.Value.market_name, id)))
.ToLookup(pair => pair.Key, pair => pair.Value);
if (marketNameToId[name].First() != null)
{
string idForMarket = marketNameToId[name].FirstOrDefault();
return idForMarket;
}
else
{
return null;
}
}
这将返回一个错误,表示序列中没有项目。
根据http://jsonformatter.curiousconcept.com/.但是,链接处的JSON是可以的,所以让我们继续这样做吧。
您想要的信息可以建模为包含两个字典的类:
public class rgInventoryItem
{
public string id { get; set; }
public string classid { get; set; }
}
public class rgDescription
{
public string classid { get; set; }
public string market_name { get; set; }
}
public class InventoryResponse
{
public Dictionary<string, rgInventoryItem> rgInventory { get; set; }
public Dictionary<string, rgDescription> rgDescriptions { get; set; }
}
然后,要从JSON字符串加载,请使用:
var response = JsonConvert.DeserializeObject<InventoryResponse>(json);
然而,rgDescriptions
字典并没有直接在classid
上建立索引,相反,密钥以某种方式与classid
相关,例如
"469449975_0":{
"classid":"469449975",
"market_name":"SG 553 | Army Sheen (Factory New)",
要从classid创建市场名称查找,可以执行
var classidToDescription = response.rgDescriptions.ToLookup(pair => pair.Value.classid);
这将找到给定classid
的所有rgDescription
类。
如果确定给定的classid
只有一个rgDescription
,则可以执行:
var classidToDescriptionDictionary = response.rgDescriptions.ToDictionary(pair => pair.Value.classid);
请注意,如果多个描述具有相同的类id,这将抛出一个ArgumentException
,并显示消息"已添加具有相同密钥的项目"。
更新
为了从market_name
转到id
,您需要反转字典并创建反向查找表。因此:
如果你需要所有的市场名称在回应,做:
var marketNames = response.rgDescriptions.Values.Select(d => d.market_name);
如果您需要响应中的所有ID,请执行:
var ids = response.rgInventory.Keys;
要从
market_name
映射到id
,首先创建反向查找:var classIdToId = response.rgInventory.ToLookup(pair => pair.Value.classid, pair => pair.Key); var marketNameToId = response.rgDescriptions .SelectMany(pair => classIdToId[pair.Value.classid].Select(id => new KeyValuePair<string, string>(pair.Value.market_name, id))) .ToLookup(pair => pair.Key, pair => pair.Value);
要获取引用给定市场名称的所有id,请执行:
var idsForMarket = marketNameToId[name].ToList();
要获得引用给定市场名称的第一个id,请执行:
var firstIdForMarket = marketNameToId[name].FirstOrDefault();
更新2
以下是您的类的修改版本:
public class rgInventoryItem
{
public string id { get; set; }
public string classid { get; set; }
}
public class rgDescription
{
public string classid { get; set; }
public string market_name { get; set; }
}
public class CSGOInventory
{
public static CSGOInventory FetchInventory(string steamId)
{
var url = "http://steamcommunity.com/profiles/" + steamId + "/inventory/json/730/2/";
return FetchInventoryFromUrl(new Uri(url));
}
public static CSGOInventory FetchInventoryFromUrl(Uri url)
{
using (WebClient client = new WebClient())
{
string response = client.DownloadString(url);
var inventory = JsonConvert.DeserializeObject<InventoryResponse>(response);
return new CSGOInventory(inventory);
}
}
readonly InventoryResponse inventory;
readonly ILookup<string, string> classIdToId;
readonly ILookup<string, string> marketNameToId;
CSGOInventory(InventoryResponse inventory)
{
if (inventory == null)
throw new ArgumentNullException();
this.inventory = inventory;
this.classIdToId = inventory.rgInventory.ToLookup(pair => pair.Value.classid, pair => pair.Key);
this.marketNameToId = inventory.rgDescriptions
.SelectMany(pair => classIdToId[pair.Value.classid].Select(id => new KeyValuePair<string, string>(pair.Value.market_name, id)))
.ToLookup(pair => pair.Key, pair => pair.Value);
}
public IDictionary<string, rgInventoryItem> InventoryItems { get { return this.inventory == null ? null : this.inventory.rgInventory; } }
public IDictionary<string, rgDescription> InventoryDescriptions { get { return this.inventory == null ? null : this.inventory.rgDescriptions; } }
public IEnumerable<string> MarketNames { get { return InventoryDescriptions == null ? null : InventoryDescriptions.Values.Select(d => d.market_name); } }
public IEnumerable<string> InventoryIds { get { return InventoryItems == null ? null : InventoryItems.Keys; } }
public string getInstanceIdFromMarketName(string name)
{
return marketNameToId[name].FirstOrDefault();
}
public IEnumerable<string> getInstanceIdsFromMarketName(string name)
{
return marketNameToId[name];
}
class InventoryResponse
{
public Dictionary<string, rgInventoryItem> rgInventory { get; set; }
public Dictionary<string, rgDescription> rgDescriptions { get; set; }
}
}
使用此,以下测试类:
public static class TestClass
{
public static void Test()
{
//string url = @"d:tempquestion28328432.json";
string url = @"http://steamcommunity.com/id/Mambocsgoshack/inventory/json/730/2/";
var inventory = CSGOInventory.FetchInventoryFromUrl(new Uri(url));
foreach (var market in inventory.MarketNames)
{
Console.WriteLine(string.Format(" Market {0,-50}: id {1}", market, inventory.getInstanceIdFromMarketName(market)));
}
}
}
给出输出
Market SG 553 | Army Sheen (Factory New) : id 1482735510
Market Offer | Music Kit | Noisia, Sharpened : id 1468698711
Market Offer | Sticker | Bomb Squad (Foil) : id 1468698710
Market Offer | Sticker | Dinked : id 1468698709
Market Offer | Sticker | Kawaii Killer CT : id 1468698708
Market Operation Breakout Weapon Case : id 1462270322
Market Operation Vanguard Weapon Case : id 1459818809
Market M4A4 | Howl (Minimal Wear) : id 1450750270
Market Operation Phoenix Weapon Case : id 1391297747
Market Negev | Army Sheen (Minimal Wear) : id 1370560151
Market Huntsman Weapon Case : id 1305163655
Market Tec-9 | Army Mesh (Minimal Wear) : id 1304896559
Market Galil AR | Cerberus (Well-Worn) : id 1214784536
Market StatTrakT Tec-9 | Sandstorm (Field-Tested) : id 1201208194
Market G3SG1 | Contractor (Field-Tested) : id 1189828757
Market Campaign Vanguard : id 1103736871
Market Campaign Weapons Specialist : id 1103736870
Market Operation Vanguard Challenge Coin : id 1103736869
Market StatTrakT XM1014 | Red Python (Field-Tested) : id 957595359
Market StatTrakT CZ75-Auto | Hexane (Field-Tested) : id 814442137
Market Negev | Army Sheen (Factory New) : id 623936007
Market SSG 08 | Sand Dune (Well-Worn) : id 616381102
Market Silver Operation Breakout Coin : id 612997861
Market UMP-45 | Scorched (Field-Tested) : id 603041123
您真正想做的是查询JSON。为此,您可以使用DixonD提出的动态对象对其进行反序列化,然后遍历您的动态对象以找到所需的信息。
另一个更简单、更干净的解决方案是使用类似jsonpath的库来查询JSON,jsonpath相当于JSON的XPath。这里有一个如何做这件事的例子。
您正试图将其反序列化为Dictionary<string, Item>
,但显然失败了,因为您有无法反序列化为Item
的元素,并且它在其中第一个元素"success": true
上失败了
你有几种方法可以继续。
-
var result = (dynamic)Newtonsoft.Json.JsonConvert.DeserializeObject(response);
在这种情况下,您可以将结果作为动态对象进行处理。
-
定义并使用与您试图反序列化的json格式相对应的类。