Is there a good way to iterate through a deserialized JSON object from last to first? i.e., the following code I can iterate and record 'n' values from first to last until it meets my count condition for further processing:
protected void testButton_Click(object sender, EventArgs e)
{
List<decimal> priceHistory = new List<decimal>();
var client = new RestClient("https://api.tdameritrade.com/v1/marketdata/" + inputSymbol + "/pricehistory?periodType=year&period=1&frequencyType=daily&frequency=1&needExtendedHoursData=false");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer " + ReadAccessToken());
request.AddParameter("text/plain", "", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
dynamic history = JsonConvert.DeserializeObject<JObject>(response.Content);
int count = 0;
foreach (var child in history["candles"])
{
count += 1;
while (count <= 100)
{
decimal close = child["close"];
priceHistory.Add(close);
break;
}
}
decimal simpleMovingAverage = priceHistory.Average();
responseLabel.Text = simpleMovingAverage.ToString();
//output is taking the first 100 close prices returned from the JSON response and averaging those values.
}
However, what I cannot find a solution to is how to begin at the last nested JSON object and add values from a back-to-front style. I am trying to reverse the aggregation from counting first nested object + 'n' next values sequential to the previous down the list, to actually taking the last nested JSON object in the response and average it with each of its previous 'n' values until the count condition has been met.
EDIT
JSON example with arbitrary 'n' period for reference:
{
"candles": [
{
"open": 172.51,
"high": 176.36,
"low": 171.5,
"close": 171.86,
"volume": 2292877,
"datetime": 1582524000000
},
{
"open": 172.18,
"high": 172.945,
"low": 165.8,
"close": 166.65,
"volume": 2358560,
"datetime": 1582610400000
},
{
"open": 168.28,
"high": 169.38,
"low": 165.61,
"close": 166.92,
"volume": 2545782,
"datetime": 1582696800000
},
{
"open": 164.4,
"high": 166.55,
"low": 159.96,
"close": 159.99,
"volume": 2957507,
"datetime": 1582783200000
},
{
"open": 155.29,
"high": 158.92,
"low": 152.66,
"close": 156.48,
"volume": 3053876,
"datetime": 1582869600000
},
{
"open": 157.92,
"high": 164.0,
"low": 156.55,
"close": 163.92,
"volume": 2532128,
"datetime": 1583128800000
}
],
"symbol": "DE",
"empty": false
}
You can use the Reverse() method of the JArray class. Just cast your history["candles"] JTokeninto a JArray, and call reverse.
void ParseJson(string json)
{
var history = JObject.Parse(json);
var candles = (history["candles"] as JArray).Reverse();
foreach (var child in candles)
{
Console.WriteLine(child["close"].ToString());
}
Console.Read();
}
Related
Is there a good way to accomplish this? I did not find any applicable solutions in searching online. With the current code implementation below, I can use the top 'n' of the returned values and break out of the loop when count is met. What I am trying to do instead, is fill the list until length has been reached (user input), and then keep that max length while cycling out the oldest with the newest values taking place of the old as in FIFO order.
private static decimal SMA(int length)
{
List<decimal> priceHistory = new List<decimal>();
var client = new RestClient("https://api.tdameritrade.com/v1/marketdata/" + inputSymbol + "/pricehistory?periodType=month&period=1&frequencyType=daily&frequency=1&needExtendedHoursData=false");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer " + ReadAccessToken());
request.AddParameter("text/plain", "", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
dynamic history = JsonConvert.DeserializeObject<JObject>(response.Content);
int count = 0;
foreach (var child in history["candles"])
{
count += 1;
while (count <= length)
{
var close = (decimal)child["close"];
priceHistory.Add(close);
break;
}
}
decimal simpleMovingAverage = priceHistory.Average();
return simpleMovingAverage;
}
So for the example data below where length is == 5, once the tenth value is reached at the end of the loop, the sixth value will have recursively cycled all the way into list[0] and the tenth value will be in list[4]:
{[
{
"open": 177.27,
"high": 178.84,
"low": 177.205,
"close": 178.7,
"volume": 1081644,
"datetime": 1613109600000
},
{
"open": 179.0,
"high": 179.69,
"low": 176.3242,
"close": 176.63,
"volume": 1834033,
"datetime": 1613455200000
},
{
"open": 176.05,
"high": 177.3,
"low": 175.14,
"close": 176.65,
"volume": 1578242,
"datetime": 1613541600000
},
{
"open": 177.25,
"high": 179.67,
"low": 176.15,
"close": 179.37,
"volume": 2088619,
"datetime": 1613628000000
},
{
"open": 179.57,
"high": 180.77,
"low": 176.2,
"close": 176.54,
"volume": 2986839,
"datetime": 1613714400000
},
{
"open": 176.46,
"high": 177.09,
"low": 175.01,
"close": 176.12,
"volume": 2271502,
"datetime": 1613973600000
},
{
"open": 177.54,
"high": 177.54,
"low": 174.71,
"close": 176.17,
"volume": 2352428,
"datetime": 1614060000000
},
{
"open": 176.0,
"high": 177.98,
"low": 173.76,
"close": 177.63,
"volume": 2742552,
"datetime": 1614146400000
},
{
"open": 177.52,
"high": 180.75,
"low": 177.43,
"close": 178.76,
"volume": 2634298,
"datetime": 1614232800000
},
{
"open": 179.44,
"high": 179.45,
"low": 174.605,
"close": 175.06,
"volume": 3363387,
"datetime": 1614319200000
}
]}
I came across queuing upon continuing to research. This actually functions exactly as required. Posting here in case it could be helpful to others.
Queue priceQueue = new Queue();
int count = 5;
foreach (var child in history["candles"])
{
var close = (decimal)child["close"];
priceQueue.Enqueue(close);
if (priceQueue.Count > count)
{
priceQueue.Dequeue();
}
}
I have two JSON objects -
json1 = {
"payload": {
"firstName": "John",
"lastName": "Doe",
"code": "test1",
"arrayProp1": [1, 2, 3],
"arrayProp2": [{
"prop1": "value1",
"prop2": "value2"
},
{
"prop1": "2_value1",
"prop2": "2_value2"
}
]
}
}
json2 = {
"payload": {
"code": "newCode",
"arrayProp1": [3,4],
"arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}
]
}
}
If I use the built-in merge (json1.Merge(json2)) the result obtained is -
result : {
"payload": {
"firstName": "John",
"lastName": "Doe",
"code": "newCode",
"arrayProp1": [1, 2, 3, 3, 4],
"arrayProp2": [{
"prop1": "value1",
"prop2": "value2"
},
{
"prop1": "newValue1",
"prop2": "newValue2"
},
{
"prop1": "2_value1",
"prop2": "2_value2"
}
]
}
}
Expected result -
{
"payload": {
"firstName": "John",
"lastName": "Doe",
"code": "newCode",
"arrayProp1": [3, 4],
"arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}]
}
}
I want to replace the parent property values of json1 based on values provided in json2.
I tried to write a function and this is the current version I have -
string Merge(string req1, string req2) {
try
{
JObject json1 = JObject.Parse(req1);
JObject json2 = JObject.Parse(req2);
foreach (var a in json2.DescendantsAndSelf())
{
if (a is JObject obj)
{
foreach (var prop in obj.Properties())
{
if(json1.SelectTokens(prop.Path).Any())
{
json1[prop.Path] = prop.Value;
}
}
}
}
req1 = json1.ToString();
}
catch(Exception ex)
{
//do nothing
}
return req1; }
There are 2 problems here -
"payload" is identified as property and json1 is replaced fully by json2 because of which I lose some of its properties.
After being replaced, when the loop continues to run, say property 'code' is to be updated, then the property path is payload.code, so on the line json1[prop.path] = prop.Value, instead of updating the existing code in the payload, it creates a new property called payload.code with value "newcode"
The final result of the code above is -
{
"payload": {
"code": "newCode",
"arrayProp1": [3, 4],
"arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}],
"payload.code": "newCode",
"payload.arrayProp1": [3, 4],
"payload.arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}],
"payload.arrayProp1[0].prop1": "newValue1",
"payload.arrayProp1[0].prop2": "newValue2"
}
}
Can someone please help me with this?
Your requirement is that array contents are replaced rather than concatenated when merging two JSON objects with JContainer.Merge(). You can achieve this via the JsonMergeSettings.MergeArrayHandling setting, which has the following values:
Concat 0 Concatenate arrays.
Union 1 Union arrays, skipping items that already exist.
Replace 2 Replace all array items.
Merge 3 Merge array items together, matched by index.
Specifically MergeArrayHandling.Replace will work as required:
json1.Merge(json2, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Replace
});
Demo fiddle here.
I'm loading some information to my Xamarin application through multiple json strings. When I run the application, it gives me this error:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[APIPost]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List
that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'postid', line 1, position 9.'
Code to get the json:
HttpClient client = new HttpClient();
var result = await client.GetStringAsync($"{APIConfig.Uri}/post/getPost/{APIConfig.Token}/{User.ID}/{User.Token}");
List<APIPost> response = JsonConvert.DeserializeObject<List<APIPost>>(result);
foreach (APIPost post in response)
{ //Code }
Class APIPost:
class APIPost
{
public string state { get; set; }
public string postid { get; set; }
public string userid { get; set; }
public string image { get; set; }
public string captation { get; set; }
public string location { get; set; }
public string date { get; set; }
public string likes { get; set; }
}
This is the json I get:
{
"postid": "2",
"userid": "2",
"image": "asdasdasd",
"captation": "asdasd",
"location": null,
"date": "2019-07-29 20:24:28",
"likes": "4"
}{
"postid": "1",
"userid": "2",
"image": "susfdfjsadv",
"captation": "This is just a test.",
"location": null,
"date": "2019-07-29 19:58:04",
"likes": "2"
}
The problem isn't with C# or with the JSON serialization library you're using. The JSON you're receiving from the server is invalid. As such, no standard JSON parsing library can be expected to successfully parse it. You'll either need to write your own, or correct the JSON to be valid.
A valid object would look like:
{
"postid": "2",
"userid": "2",
"image": "asdasdasd",
"captation": "asdasd",
"location": null,
"date": "2019-07-29 20:24:28",
"likes": "4"
}
And a valid array of objects would look like:
[
{
"postid": "2",
"userid": "2",
"image": "asdasdasd",
"captation": "asdasd",
"location": null,
"date": "2019-07-29 20:24:28",
"likes": "4"
},
{
"postid": "1",
"userid": "2",
"image": "susfdfjsadv",
"captation": "This is just a test.",
"location": null,
"date": "2019-07-29 19:58:04",
"likes": "2"
}
]
There's no such thing as "multiple JSON" within the same structure. You either have a valid structure or you don't. You can certainly have multiple structures, but you can't have them all mashed together into one like that.
In short... fix the server-side code to send a valid response.
Have you any control over the source of that json?
You need to provide something like:
[
{...},
{...}
]
And you will be fine
As #lasse-v-karlsen says in a comment, the server should be fixed but there's a way to parse this with Newtonsoft.Json (in case we're in one of those JSON-streaming scenarios):
using (var file = new StreamReader(#"D:\Temp\test.json", Encoding.UTF8))
using (var reader = new Newtonsoft.Json.JsonTextReader(file))
{
reader.SupportMultipleContent = true;
var serializer = JsonSerializer.CreateDefault();
serializer.Deserialize(reader).Dump();
while (reader.Read())
serializer.Deserialize(reader).Dump();
}
In case you're not fond on adding the dependency to json.net, then I've cooked a very simple JSON splitter:
IEnumerable<string> SplitJsonStream(string jsonString)
{
IEnumerable<string> splitJsonStreamInner(char? head, string tail, uint braceNestingLevel, bool insideSubString, string acc)
{
if (!head.HasValue)
{
if (braceNestingLevel != 0)
throw new ArgumentException("jsonString seems to be invaid");
yield break;
}
char? newHead = null;
string newAcc = null;
if (!String.IsNullOrEmpty(tail))
{
newHead = tail.First();
}
if (head.HasValue)
{
newAcc = acc + head.Value;
}
var newTail = newHead == null ? null : tail.Substring(1);
if (!insideSubString && head == '"') {
foreach(var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel, true, newAcc))
yield return subAcc;
yield break;
}
if (insideSubString)
{
if (head == '"')
{
foreach (var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel, false, newAcc))
yield return subAcc;
yield break;
}
foreach (var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel, insideSubString, newAcc))
yield return subAcc;
yield break;
}
if (head == '{')
{
foreach (var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel + 1, insideSubString, newAcc))
yield return subAcc;
yield break;
}
else if (head == '}')
{
if (braceNestingLevel == 0)
throw new ArgumentException("jsonString seems to be invalid");
var newNestingLevel = braceNestingLevel - 1;
if (newNestingLevel == 0) {
yield return newAcc;
newAcc = String.Empty;
}
foreach (var subAcc in splitJsonStreamInner(newHead, newTail, newNestingLevel, insideSubString, newAcc))
yield return subAcc;
yield break;
}
else
{
foreach (var subAcc in splitJsonStreamInner(newHead, newTail, braceNestingLevel, insideSubString, newAcc))
yield return subAcc;
yield break;
}
}
jsonString = jsonString.Trim();
if (jsonString == string.Empty)
yield break;
if (!jsonString.StartsWith("{"))
throw new ArgumentException("jsonString should start with {");
if (!jsonString.EndsWith("}"))
throw new ArgumentException("jsonString should end with }");
foreach (var sub in splitJsonStreamInner(jsonString.First(), jsonString.Substring(1), 0, false, String.Empty))
yield return sub;
}
The proof that the above works is this unit test:
[Fact()]
public void JsonSplitterTests()
{
Assert.Empty(SplitJsonStream(String.Empty));
Assert.Throws<ArgumentException>(() => SplitJsonStream("x").Count()); // not startswith {
Assert.Throws<ArgumentException>(() => SplitJsonStream("{x").Count()); // not endswith }
var fooJson = "{ \"foo\": 1 }";
var splitted = SplitJsonStream(fooJson);
Assert.Equal(1, splitted.Count());
Assert.Equal(fooJson, splitted.ElementAt(0));
var barJson = "{ \"bar\": 2 }";
splitted = SplitJsonStream(fooJson + barJson);
Assert.Equal(2, splitted.Count());
Assert.Equal(fooJson, splitted.ElementAt(0));
Assert.Equal(barJson, splitted.ElementAt(1));
var bazJson = "{ \"baz\": 3 }";
splitted = SplitJsonStream(fooJson + barJson + bazJson);
Assert.Equal(3, splitted.Count());
Assert.Equal(fooJson, splitted.ElementAt(0));
Assert.Equal(barJson, splitted.ElementAt(1));
Assert.Equal(bazJson, splitted.ElementAt(2));
// ends with bad nesting level
Assert.Throws<ArgumentException>(() => SplitJsonStream("{{x}").Count());
Assert.Throws<ArgumentException>(() => SplitJsonStream("{x}}").Count());
// edge case
Assert.Equal(1, SplitJsonStream("{ \"foo\": \"{\" }").Count());
//whitespace in front
Assert.Equal(2, SplitJsonStream("\n{ \"foo\": 1 }{ \"bar\": 2 }").Count());
Assert.Equal(2, SplitJsonStream("\r\n{ \"foo\": 1 }{ \"bar\": 2 }").Count());
Assert.Equal(2, SplitJsonStream("\t{ \"foo\": 1 }{ \"bar\": 2 }").Count());
Assert.Equal(2, SplitJsonStream(" { \"foo\": 1 }{ \"bar\": 2 }").Count());
//whitespace at the end
Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }{ \"bar\": 2 }\n").Count());
Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }{ \"bar\": 2 }\r\n").Count());
Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }{ \"bar\": 2 }\t").Count());
Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }{ \"bar\": 2 } ").Count());
//whitespace in the middle
Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }\n{ \"bar\": 2 }").Count());
Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }\r\n{ \"bar\": 2 }").Count());
Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 }\t{ \"bar\": 2 }").Count());
Assert.Equal(2, SplitJsonStream("{ \"foo\": 1 } { \"bar\": 2 }").Count());
}
I want to parse JSON in this format
json result:{
"time": 23,
"npc":[
{
"id":1,
"b_box" {
"left": 250,
"top": 135,
},
},
{
"id":2,
"b_box" {
"left": 234,
"top": 343,
},
},
{
"id":3,
"b_box" {
"left": 342,
"right": 543,
}
}
]
}
Here is my code for parsing
void extractD (string jsonResult) {
JSONNode incomingData = SimpleJSON.JSON.Parse(jsonResult);
JSONArray npc = incomingData ["npc"].AsArray;
foreach (JSONNode bBox in npc) {
int bLeft = bBox ["b_box"]["left"];
int bTop = bBox ["b_box"]["top"];
}
I want to initialize variables with the left and top values for id:1 id:2 and id:3 separately how should I modify my code to accomplish this? Code examples would be much appreciated.
I have a JSON string that I need to make it nicer in C#. I tried the code from here:
JSON formatter in C#?
that is a class I used in my project:
class JsonHelper
{
private const string INDENT_STRING = " ";
public static string FormatJson(string str)
{
var indent = 0;
var quoted = false;
var sb = new StringBuilder();
for (var i = 0; i < str.Length; i++)
{
var ch = str[i];
switch (ch)
{
case '{':
case '[':
sb.Append(ch);
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, ++indent).ForEach(item => sb.Append(INDENT_STRING));
}
break;
case '}':
case ']':
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, --indent).ForEach(item => sb.Append(INDENT_STRING));
}
sb.Append(ch);
break;
case '"':
sb.Append(ch);
bool escaped = false;
var index = i;
while (index > 0 && str[--index] == '\\')
escaped = !escaped;
if (!escaped)
quoted = !quoted;
break;
case ',':
sb.Append(ch);
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, indent).ForEach(item => sb.Append(INDENT_STRING));
}
break;
case ':':
sb.Append(ch);
if (!quoted)
sb.Append(" ");
break;
default:
sb.Append(ch);
break;
}
}
return sb.ToString();
}
}
static class Extensions
{
public static void ForEach<T>(this IEnumerable<T> ie, Action<T> action)
{
foreach (var i in ie)
{
action(i);
}
}
}
and in my page I have this code to call the class and write a string on the screen.
IRestResponse response5 = GetCampaigns();
string formattedJason = JsonHelper.FormatJson(response5.Content.ToString());
Response.Write(formattedJason);
My problem is that the formatted Json doesnt have a line break so it is like this:
{ "total_count": 10, "items": [ { "clicked_count": 2559, "opened_count": 7021, "submitted_count": 3102, "unsubscribed_count": 0, "bounced_count": 4, "id": "3", "name": "Approved Email", "created_at": "Wed, 09 Oct 2013 17:16:35 GMT", "delivered_count": 2984, "complained_count": 0, "dropped_count": 118 }, { "clicked_count": 240, "opened_count": 434, "submitted_count": 183, "unsubscribed_count": 0, "bounced_count": 0, "id": "5", "name": "Ready to Shop", "created_at": "Wed, 09 Oct 2013 00:21:08 GMT", "delivered_count": 181, "complained_count": 0, "dropped_count": 2 } ] }
How I can get a nicer Json something like:
{
"status" : "OK",
"results" : [
{
"types" : [
"locality",
"political"
],
"formatted_address" : "New York, NY, USA",
"address_components" : [
{
"long_name" : "New York",
"short_name" : "New York",
"types" : [
"locality",
"political"
]
},
You can just put the text to notepad++ and use JSMin plugin to format the json string. Or JSON.Net is a solution for you.