JSON Format in C# - c#

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.

Related

How to convert list of fields into json object [duplicate]

This question already has an answer here:
Convert dot notation to JSON
(1 answer)
Closed last year.
I have list of fields as a string:
[
"Container.Description",
"Container.Groups.12.Users.11.Name",
"Container.Groups.12.Users.12.Name",
"Container.Groups.13.Users.21.Name",
"Container.Groups.13.Users.22.Name"
]
Is there a way to convert this array of fields to json object like:
{
"Container": {
"Description": "",
"Groups": [
{
"12": {
"Users": [
{ "11": { "Name": "" }},
{ "12": { "Name": "" }}
]
}
},
{
"13": {
"Users": [
{ "21": { "Name": "" }},
{ "22": { "Name": "" }}
]
}
}
]
}
}
I need this code into typescript or c#.
Thanks in advance.
It maybe not a very good solution, but it indeed works...
handleData(data: string[]) {
const res = {};
data.forEach(dataItem => this.changeObjectByStr(res, dataItem));
return res;
}
private changeObjectByStr(currentObject: { [key: string]: any }, str: string) {
const keyList = str.split('.');
let usedObject = currentObject;
for (let i = 0; i < keyList.length; i++) {
const key = keyList[i];
// The key existed
if (usedObject[key]) {
usedObject = usedObject[key];
continue;
}
// The key not exist:
// This is the last key
if (i === keyList.length - 1) {
usedObject[key] = '';
} else {
// This is not the last key
usedObject[key] = {};
usedObject = usedObject[key];
}
}
}

C# Iterate from Last JSON Object to First

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();
}

How to deserialize multiple json in C#?

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());
}

Using C# and simpleJSON how do I access data in this array

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.

The Replace method not working ,C#

I'm working on a phone number converter code with C# ,struggling with replacing any alphabetic character to its corresponding number on the phone keys.In the code down here ,the variable result already has a 10 characters ,wich is a mix of numbers and letters.As you see in the code ,I'm trying to use the Replace method through out the switch case,but it gives me wrong results .Any ideas ?Thanks.
Sorry I forgot to mention that Arrays are not allowed to be used in this project,only conditions and repeatition.Ah ,and it's console C#.
for (int i = 0; i < result.Length; i++)
{
switch (buffer)
{
case "A":
case "B":
case "C": myNumber = result.Replace(buffer, "2");
break;
case "D":
case "E":
case "F": myNumber = result.Replace(buffer, "3");
break;
case "G":
case "H":
case "I": myNumber = result.Replace(buffer, "4");
break;
case "J":
case "K":
case "L": myNumber = result.Replace(buffer, "5");
break;
case "M":
case "N":
case "O": myNumber = result.Replace(buffer, "6");
break;
case "P":
case "Q":
case "R":
case "S": myNumber = result.Replace(buffer, "7");
break;
case "T":
case "U":
case "V": myNumber = result.Replace(buffer, "8");
break;
case "W":
case "X":
case "Y":
case "Z": myNumber = result.Replace(buffer, "9");
break;
}
Console.WriteLine("({0})-{1}-{2}", myNumber.Substring(0, 3), myNumber.Substring(3, 3), myNumber.Substring(6, 4));
You're assigning Replace method result to myNumber, but in next loop iteration you're taking result as Replace parameter again. It can't work.
How about that:
private static readonly Dictionary<string, string> PhoneReplacements =
new Dictionary<string, string>() {
{ "A", "1" }, { "B", "1" }, { "C", "1" },
{ "D", "2" }, { "E", "2" }, { "F", "2" },
{ "G", "3" }, { "H", "3" }, { "I", "3" }
// (...)
};
private static string GetPhoneNumber(string number)
{
foreach(var r in PhoneReplacements)
{
number = number.Replace(r.Key, r.Value);
}
return number;
}
String are immutable. When you do
result.Replace(buffer, "9");
result does not change.
So, you are only using the replacement of the last iteration, not the combination of all the replacements that your code has done. That is what you are assigning to your code.
Instead of
myNumber = result.Replace(buffer, "9");
do
result = result.Replace(buffer, "9");
or even, if you wish
myNumber = result = result.Replace(buffer, "9");
Consider the following rewrite...
string result = "1800CALLME";
string myNumber = string.Empty;
for (int i = 0; i < result.Length; i++)
{
string buffer = result[i].ToString();
switch (buffer)
{
case "A":
case "B":
case "C": myNumber += "2";
break;
case "D":
case "E":
case "F": myNumber += "3";
break;
case "G":
case "H":
case "I": myNumber += "4";
break;
case "J":
case "K":
case "L": myNumber += "5";
break;
case "M":
case "N":
case "O": myNumber += "6";
break;
case "P":
case "Q":
case "R":
case "S": myNumber += "7";
break;
case "T":
case "U":
case "V": myNumber += "8";
break;
case "W":
case "X":
case "Y":
case "Z": myNumber += "9";
break;
}
Console.WriteLine("({0})-{1}-{2}", myNumber.Substring(0, 3), myNumber.Substring(3, 3), myNumber.Substring(6, 4));
Good Luck!
Do remember to use StringBuilder when building strings, especialy when building strings in iterations.
private static readonly Dictionary<Char, Byte> mappings = new Dictionary<Char, Byte>() {
{ 'A', 2 }, { 'B', 2 }, { 'C', 2 },
{ 'D', 3 }, { 'E', 3 }, { 'F', 3 },
{ 'G', 4 }, { 'H', 4 }, { 'I', 4 },
{ 'J', 5 }, { 'K', 5 }, { 'L', 5 },
{ 'M', 6 }, { 'N', 6 }, { 'O', 6 },
{ 'P', 7 }, { 'Q', 7 }, { 'R', 7 }, { 'S', 7 },
{ 'T', 8 }, { 'U', 8 }, { 'V', 8 },
{ 'W', 9 }, { 'X', 9 }, { 'Y', 9 }, { 'Z', 9},
{ ' ', 0 }
};
private static string StringToKeystrokes(string s)
{
StringBuilder sb = new StringBuilder();
foreach (char c in s)
{
if (mappings.ContainsKey(c))
{
sb.Append(mappings[c]);
}
}
return sb.ToString();
}
Using the code.
string s = "ABC DEF GHI JKL MNO PQRS TUV WXYZ";
Console.WriteLine(s);
Console.WriteLine(StringToKeystrokes(s));

Categories

Resources