I am using Newtonsoft JSON to parse some output from an API. However, the API result is nearly 2.5 MB, and parsing out the entire file just to find the data I need takes a long time. Here is a snippet of the API output:
{
"response": {
"success": 1,
"current_time": 1416085203,
"raw_usd_value": 0.2,
"usd_currency": "metal",
"usd_currency_index": 5002,
"items": {
"A Brush with Death": {
"defindex": [
30186
],
"prices": {
"6": {
"Tradable": {
"Craftable": [
{
"currency": "metal",
"value": 3,
"last_update": 1414184620,
"difference": -0.165
}
]
}
}
}
},
My code is supposed to find the only object that is a child of the items object with the number '5021' in the defindex array, and pull out the currency and value data. Here is the code I use to find the data:
dynamic result = Newtonsoft.Json.JsonConvert.DeserializeObject(priceFile);
int keyprice = 0;
foreach(var items in result.response.items){
foreach(var item in items){
string indexstr = item.defindex.ToString();
if (indexstr.Contains(defindex))
{
foreach(var price in item.prices){
foreach (var quality in price)
{
Console.WriteLine("{0} {1}", quality.Tradable.Craftable[0].value, quality.Tradable.Craftable[0].currency);
keyprice = quality.Tradable.Craftable[0].value;
return keyprice;
}
}
}
}
}
Ideally, the code should only take up to 10 seconds to run.
I would create an class for response object, and then use code similar to the following. I tested on a 2.8MB json file and it averaged about 1.2 second, also try using fastJSON (there is a nuget package) - it is the fastest parser I have found.
string fileName = #"c:\temp\json\yourfile.json";
string json;
using (StreamReader sr = new StreamReader(fileName))
{
json = sr.ReadToEnd();
}
response myResponse = fastJSON.JSON.ToObject<response>(json);
var item = myResponse.First(i => i.defindex == "5051");
foreach (var price in item.prices)
{
foreach (var quality in price)
{
Console.WriteLine("{0} {1}", quality.Tradable.Craftable[0].value, quality.Tradable.Craftable[0].currency);
keyprice = quality.Tradable.Craftable[0].value;
return keyprice;
}
}
Related
I need help extracting and returning values from json as either doubles or string, either should be fine.
The URL being used it: <https://earthquake.usgs.gov/ws/designmaps/asce7-16.json?latitude=34&longitude=-118&riskCategory=III&siteClass=C&title=Example>
here is the json
{
"request": {
"date": "2021-01-30T19:07:52.176Z",
"referenceDocument": "ASCE7-16",
"status": "success",
"url": "https://earthquake.usgs.gov/ws/designmaps/asce7-16.json?latitude=34&longitude=-118&riskCategory=III&siteClass=C&title=Example",
"parameters": {
"latitude": 34,
"longitude": -118,
"riskCategory": "III",
"siteClass": "C",
"title": "Example"
}
},
"response": {
"data": {
"pgauh": 0.819,
"pgad": 1.021,
"pga": 0.819,
"fpga": 1.2,
"pgam": 0.983,
"ssrt": 1.888,
"crs": 0.896,
"ssuh": 2.106,
"ssd": 2.432,
"ss": 1.888,
"fa": 1.2,
"sms": 2.265,
"sds": 1.51,
"sdcs": "D",
"s1rt": 0.669,
"cr1": 0.9,
"s1uh": 0.743,
"s1d": 0.963,
"s1": 0.669,
"fv": 1.4,
"sm1": 0.936,
"sd1": 0.624,
"sdc1": "D",
"sdc": "D",
"tl": 8,
"t-sub-l": 8,
"cv": 1.278,
...
url is defined as an input and Ss and S1 are defined as outputs per VisualStudio 2019 grasshopper developer C# template.
right now Ss and S1 return null values, they should return 1.888 and 0.669, respectively.
using Grasshopper.Kernel;
using System;
using System.Net;
using Newtonsoft.Json.Linq;
protected override void SolveInstance(IGH_DataAccess DA)
{
string url = "";
DA.GetData(0, ref url);
using (WebClient wc = new WebClient())
{
var json = wc.DownloadString(url);
JObject jObj = JObject.Parse(json); // Parse the object graph
string Ss = (string)jObj["ss"];
string S1 = (string)jObj["s1"];
//Functions I also tried
//var data = jObj["data"];
//foreach (var d in data) ;
//var Ss = d["ss"];
//double Ss = jObj.GetValue("ss").ToObject<double>();
//string Ss = jObj.GetValue("ss").Value<string>();
//string Ss = jObj.GetValue("ss").ToString();
//string Ss = jObj["ss"].ToString();
DA.SetData(0, Ss);
DA.SetData(1, S1);
}
}
The information you are looking for is nested in two levels, you have to access the response object then the data object, this should work:
var json = wc.DownloadString(url);
JObject jObj = JObject.Parse(json); // Parse the object graph
var data = jObj["response"]["data"];
var ss = data["ss"].ToObject<double>(); // or .ToString() if you want the string value
var s1 = data["s1"].ToObject<double>(); // or .ToString() if you want the string value
DA.SetData(0, ss);
DA.SetData(1, s1);
note: this code lacks null checks and error handling (try-catch block) for the sake of simplicity. But you need to add that in your code.
your data is null, is because your need Deserilize Json
using httpclientFactory
var httpclient = _httpClientFactory.CreateClient();
var responseDatas = await httpclient.GetAsync("https://earthquake.usgs.gov/ws/designmaps/asce7-16.json?latitude=34&longitude=-118&riskCategory=III&siteClass=C&title=Example");
if (responseDatas.IsSuccessStatusCode)
{
var responseDatasJson = await responseDatas .Content.ReadAsStringAsync();
var options = new JsonSerializerOptions() { PropertyNameCaseInsensitive = true };
var resultDataJson = JsonSerializer.Deserialize<Root>(responseDatasJson, options);
return (resultDataJson);
}
for convert json to c# class use this site Json to c# class
or use visual studio options
Edit-->Paste Special-->Paste Json As Classes
public class Data {
public double ss{ get; set; }
public double s1{ get; set; }
....your properties
}
public class Response {
public Data data { get; set; }
}
public class Root {
public Response response { get; set; }
}
Input json
{
"ErrorMessage":"Transaction has been authorized successfully",
"ControlId":1000.00,
"Authorizations":[
{
"RMATranUUID":"1c1a88f7-d6cf-4ae8-87d3-ba06e9d9fe36",
"Payments":[
{
"PaymentNumber":"1",
"TotalPaymentsNumber":24,
"AmountDue":1000.0,
"AmountPaid":0.00
}
],
"Term":24,
"OTBReleaseAmount":null
},
{
"RMATranUUID":"b012ba9c-2dbd-4961-8959-ec0afbafbe13",
"OTBReleaseAmount":null
}
]
}
Output json, after parsing
JObject jsonPacket = JObject.Parse(inputString);
//Line no second changes 1000.00 to 1000.0
{
"ErrorMessage":"Transaction has been authorized successfully",
"ControlId":1000.0,
"Authorizations":[
{
"RMATranUUID":"1c1a88f7-d6cf-4ae8-87d3-ba06e9d9fe36",
"Payments":[
{
"PaymentNumber":"1",
"TotalPaymentsNumber":24,
"AmountDue":1000.0,
"AmountPaid":0.00
}
],
"Term":24,
"OTBReleaseAmount":null
},
{
"RMATranUUID":"b012ba9c-2dbd-4961-8959-ec0afbafbe13",
"OTBReleaseAmount":null
}
]
}
The reason is JObject at parsing doubles executes like this under the hood:
double data;
double.TryParse("1214.00", NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out data);
As data is of type double and double is floating point number, you didn't get the value you expect.
Either, you create a POCO and parse it into it, or you can do this:
string json = "{ \"ErrorMessage\":\"Transaction has been authorized successfully\", \"ControlId\":1000.00, \"Authorizations\":[ { \"RMATranUUID\":\"1c1a88f7-d6cf-4ae8-87d3-ba06e9d9fe36\", \"Payments\":[ { \"PaymentNumber\":\"1\", \"TotalPaymentsNumber\":24, \"AmountDue\":1000.0, \"AmountPaid\":0.00 } ], \"Term\":24, \"OTBReleaseAmount\":null }, { \"RMATranUUID\":\"b012ba9c-2dbd-4961-8959-ec0afbafbe13\", \"OTBReleaseAmount\":null } ]}";
var jsonReader = new JsonTextReader(new StringReader(json));
jsonReader.FloatParseHandling = FloatParseHandling.Decimal;
var jObject = JObject.Load(jsonReader);
Console.WriteLine(jObject["ControlId"].Value<decimal>()); // 1000.00
Console.WriteLine(jObject); // prints your actual json
I had a json-structure with unkown keys.
Here is a random example:
{
"menu": {
"header": "xProgress SVG Viewer",
"items": [
{
"id": "Open"
},
{
"id": "OpenNew",
"label": "Open New"
}
}
Now I want to read all data and do some action for each value.
I found 2 methods, but both not easy to handle:
object obj = JsonConvert.DeserializeObject(data);
foreach (var prop in obj.GetType().GetProperties())
if (prop.GetIndexParameters().Count() == 0)
//Access with 'prop.Name' and 'prop.GetValue(obj, null)'
//But Iam not able to handle this correctly
and
using (var reader = new JsonTextReader(new System.IO.StringReader(data)))
while (reader.Read())
//Access with 'reader.Value'
//Complex - next picture
string.Format("{0} - {1} - {2}", reader.TokenType, reader.ValueType, reader.Value)
Its to complex to work on this data (arrays are also possible). Any ideas?
I have some JSON Data which looks like this:
{
"response":{
"_token":"StringValue",
"code":"OK",
"user":{
"userid":"2630944",
"firstname":"John",
"lastname":"Doe",
"reference":"999999999",
"guid":"StringValue",
"domainid":"99999",
"username":"jdoe",
"email":"jdoe#jdoe.edu",
"passwordquestion":"",
"flags":"0",
"lastlogindate":"2013-02-05T17:54:06.31Z",
"creationdate":"2011-04-15T14:40:07.22Z",
"version":"3753",
"data":{
"aliasname":{
"$value":"John Doe"
},
"smsaddress":{
"$value":"5555555555#messaging.sprintpcs.com"
},
"blti":{
"hideemail":"false",
"hidefullname":"false"
},
"notify":{
"grades":{
"$value":"0"
},
"messages":{
"$value":"1"
}
},
"beta_component_courseplanexpress_1":{
"$value":"true"
}
}
}
}
I am using C# with JSON.NET to parse through the data. I've been able to sucessfully get data using this algorithm:
User MyUser = new User();
JToken data = JObject.Parse(json);
MyUser.FirstName = (string) data.SelectToken("response.user.firstname");
//The same for all the other properties.
The problem is with the data field. This field is based on user preferences mostly and data is only inserted as it is used. The fields are all custom and developers can put in as many as they want without restrictions. Essentially, it's all free form data. Also as you notice they can be nested really far with data.
I've tried to run:
MyUser.Data = JsonConvert.DeserializeObject<List<JToken>>((string) data.SelectToken("response.user.data");
which doesn't work.
How would you go about converting it to be used in a C# object?
You can access it via the JToken / JArray / JObject methods. For example, this will list all of the keys under the data:
public class StackOverflow_14714085
{
const string JSON = #"{
""response"": {
""_token"": ""StringValue"",
""code"": ""OK"",
""user"": {
""userid"": ""2630944"",
""firstname"": ""John"",
""lastname"": ""Doe"",
""reference"": ""999999999"",
""guid"": ""StringValue"",
""domainid"": ""99999"",
""username"": ""jdoe"",
""email"": ""jdoe#jdoe.edu"",
""passwordquestion"": """",
""flags"": ""0"",
""lastlogindate"": ""2013-02-05T17:54:06.31Z"",
""creationdate"": ""2011-04-15T14:40:07.22Z"",
""version"": ""3753"",
""data"": {
""aliasname"": {
""$value"": ""John Doe""
},
""smsaddress"": {
""$value"": ""5555555555#messaging.sprintpcs.com""
},
""blti"": {
""hideemail"": ""false"",
""hidefullname"": ""false""
},
""notify"": {
""grades"": {
""$value"": ""0""
},
""messages"": {
""$value"": ""1""
}
},
""beta_component_courseplanexpress_1"": {
""$value"": ""true""
}
}
}
}
}";
public static void Test()
{
var jo = JObject.Parse(JSON);
var data = (JObject)jo["response"]["user"]["data"];
foreach (var item in data)
{
Console.WriteLine("{0}: {1}", item.Key, item.Value);
}
}
}
Json.NET can actually parse to a dynamic if that is useful to you.
Which means you can do something like.
dynamic parsedObject = JsonConvert.DeserializeObject("{ test: \"text-value\" }");
parsedObject["test"]; // "text-value"
parsedObject.test; // "text-value"
parsedObject.notHere; // null
Edit: might be more suitable for you to iterate the values if you don't know what you are looking for though.
dynamic parsedObject = JsonConvert.DeserializeObject("{ test: { inner: \"text-value\" } }");
foreach (dynamic entry in parsedObject)
{
string name = entry.Name; // "test"
dynamic value = entry.Value; // { inner: "text-value" }
}
I'm working on a project in C# in which I want to enter a search term, hit the search button and then retrieve parts of the response from Google to an array so I can iterate through them.
Searching Google using their JSON-based API is pretty easy
var client = new HttpClient();
var address = new Uri("https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=" + term);
HttpResponseMessage response = await client.GetAsync(address);
String stream = await response.Content.ReadAsStringAsync();
This returns a JSON string like the one below (Results for the term "Test search")
{
"responseData":{
"results":[
{
"GsearchResultClass":"GwebSearch",
"unescapedUrl":"http://en.wikipedia.org/wiki/Wikipedia:Search_engine_test",
"url":"http://en.wikipedia.org/wiki/Wikipedia:Search_engine_test",
"visibleUrl":"en.wikipedia.org",
"cacheUrl":"http://www.google.com/search?q\u003dcache:g6KEStELS_MJ:en.wikipedia.org",
"title":"Wikipedia:\u003cb\u003eSearch\u003c/b\u003eengine\u003cb\u003etest\u003c/b\u003e-Wikipedia,thefreeencyclopedia",
"titleNoFormatting":"Wikipedia:Searchenginetest-Wikipedia,thefreeencyclopedia",
"content":"A\u003cb\u003esearch\u003c/b\u003eengine\u003cb\u003etest\u003c/b\u003ecannothelpyouavoidtheworkofinterpretingyourresultsanddecidingwhattheyreallyshow.Appearanceinanindexaloneisnotusually\u003cb\u003e...\u003c/b\u003e"
},
{
"GsearchResultClass":"GwebSearch",
"unescapedUrl":"http://techcrunch.com/2008/07/16/google-continues-to-test-a-search-interface-that-looks-more-like-digg-every-day/",
"url":"http://techcrunch.com/2008/07/16/google-continues-to-test-a-search-interface-that-looks-more-like-digg-every-day/",
"visibleUrl":"techcrunch.com",
"cacheUrl":"http://www.google.com/search?q\u003dcache:r2laSUVQw8kJ:techcrunch.com",
"title":"GoogleContinuesTo\u003cb\u003eTest\u003c/b\u003eA\u003cb\u003eSearch\u003c/b\u003eInterfaceThatLooksMoreLike\u003cb\u003e...\u003c/b\u003e",
"titleNoFormatting":"GoogleContinuesToTestASearchInterfaceThatLooksMoreLike...",
"content":"Jul16,2008\u003cb\u003e...\u003c/b\u003eAcoupleofdaysagowepostedscreenshotsofanew\u003cb\u003esearch\u003c/b\u003einterfacebeingbucket\u003cb\u003etested\u003c/b\u003ebyGooglethatletsusersvoteupordownon\u003cb\u003e...\u003c/b\u003e"
},
{
"GsearchResultClass":"GwebSearch",
"unescapedUrl":"http://googleblog.blogspot.com/2006/04/this-is-test-this-is-only-test.html",
"url":"http://googleblog.blogspot.com/2006/04/this-is-test-this-is-only-test.html",
"visibleUrl":"googleblog.blogspot.com",
"cacheUrl":"http://www.google.com/search?q\u003dcache:Ozl1cQzRT0IJ:googleblog.blogspot.com",
"title":"Thisisa\u003cb\u003etest\u003c/b\u003e.Thisisonlya\u003cb\u003etest\u003c/b\u003e.|OfficialGoogleBlog",
"titleNoFormatting":"Thisisatest.Thisisonlyatest.|OfficialGoogleBlog",
"content":"Apr24,2006\u003cb\u003e...\u003c/b\u003eFromtimetotime,werunliveexperimentsonGoogle—\u003cb\u003etests\u003c/b\u003evisibletoarelativelyfewpeople--todiscoverbetterwaysto\u003cb\u003esearch\u003c/b\u003e.Wedothis\u003cb\u003e...\u003c/b\u003e"
},
{
"GsearchResultClass":"GwebSearch",
"unescapedUrl":"http://alistapart.com/article/testing-search-for-relevancy-and-precision",
"url":"http://alistapart.com/article/testing-search-for-relevancy-and-precision",
"visibleUrl":"alistapart.com",
"cacheUrl":"http://www.google.com/search?q\u003dcache:02Sjrd5mb0YJ:alistapart.com",
"title":"\u003cb\u003eTestingSearch\u003c/b\u003eforRelevancyandPrecision·AnAListApartArticle",
"titleNoFormatting":"TestingSearchforRelevancyandPrecision·AnAListApartArticle",
"content":"Sep22,2009\u003cb\u003e...\u003c/b\u003eDespitethefactthatsite\u003cb\u003esearch\u003c/b\u003eoftenreceivesthemosttraffic,it\u0026#39;salsotheplacewheretheuserexperiencedesignerbearstheleastinfluence."
}
],
"cursor":{
"resultCount":"1,010,000,000",
"pages":[
{
"start":"0",
"label":1
},
{
"start":"4",
"label":2
},
{
"start":"8",
"label":3
},
{
"start":"12",
"label":4
},
{
"start":"16",
"label":5
},
{
"start":"20",
"label":6
},
{
"start":"24",
"label":7
},
{
"start":"28",
"label":8
}
],
"estimatedResultCount":"1010000000",
"currentPageIndex":0,
"moreResultsUrl":"http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den\u0026q\u003dTest+search",
"searchResultTime":"0.23"
}
},
"responseDetails":null,
"responseStatus":200
}
How do I get the value of url in each node pushed into an array so I can iterate through it?
You can use dynamic keyword with Json.Net
dynamic jObj = JsonConvert.DeserializeObject(json);
foreach (var res in jObj.responseData.results)
{
Console.WriteLine("{0} => {1}\n",res.title,res.url);
}
You can use Linq too
var jObj = (JObject)JsonConvert.DeserializeObject(json);
string[] urls = jObj["responseData"]["results"]
.Select(x => (string)x["url"])
.ToArray();