C# Sort JSON string keys - c#

I'd like to convert the JSON string
"{ \"birthday\": \"1988-03-18\", \"address\": { \"state\": 24, \"city\": 8341, \"country\": 1 } }"
to
"{ \"address\": { \"city\": 8341, \"country\": 1, \"state\": 24 }, \"birthday\": \"1988-03-18\" }"
NOTE: I'm not using the sorted version for communication (because the key order doesn't really matter), I need a sorted version to perform local tests (by comparing JSON strings).
EDIT: I4V pointed a solution that uses Json.Net, I would rather use a solution that doesn't need to include any 3rd party library (actually I'm using the built in System.Json in my application)
I posted a gist with the solution provided by I4V + some testing here. Thank you all.

I will use Json.Net for this
string json = #"{ ""birthday"": ""1988-03-18"", ""address"": { ""state"": 24, ""city"": 8341, ""country"": 1 } }";
var jObj = (JObject)JsonConvert.DeserializeObject(json);
Sort(jObj);
string newJson = jObj.ToString();
void Sort(JObject jObj)
{
var props = jObj.Properties().ToList();
foreach (var prop in props)
{
prop.Remove();
}
foreach (var prop in props.OrderBy(p=>p.Name))
{
jObj.Add(prop);
if(prop.Value is JObject)
Sort((JObject)prop.Value);
}
}
EDIT
A try with System.Json but I am not sure about OrderByDescending ( or OrderBy).
var jObj = (System.Json.JsonObject)System.Json.JsonObject.Parse(json);
Sort2(jObj);
var newJson = jObj.ToString();
void Sort2(System.Json.JsonObject jObj)
{
var props = jObj.ToList();
foreach (var prop in props)
{
jObj.Remove(prop.Key);
}
foreach (var prop in props.OrderByDescending(p => p.Key))
{
jObj.Add(prop);
if (prop.Value is System.Json.JsonObject)
Sort2((System.Json.JsonObject)prop.Value);
}
}

I know this may be a little late but, in case of you need to sort the internal arrays of data too (I just needed it):
static void Sort(JObject jObj)
{
var props = jObj.Properties().ToList();
foreach (var prop in props)
{
prop.Remove();
}
foreach (var prop in props.OrderBy(p => p.Name))
{
jObj.Add(prop);
if (prop.Value is JObject)
Sort((JObject)prop.Value);
if (prop.Value is JArray)
{
Int32 iCount = prop.Value.Count();
for (Int32 iIterator = 0; iIterator < iCount; iIterator++)
if (prop.Value[iIterator] is JObject)
Sort((JObject)prop.Value[iIterator]);
}
}
}
Cheers!

By using this approach you can retrieve a dynamic object with your json data
At the DynamicJsonConverter create a SortedDictionary instead
var d = new SortedDictionary<string, object>(dictionary);
// TODO: code to sort inner objects
return new DynamicJsonObject(d);
Then you can use
string jsonStr = "{\"B\":\"2\",\"A\":\"1\"}";
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });
dynamic json = jss.Deserialize(jsonStr, typeof(object)) as dynamic;
string result = new JavaScriptSerializer().Serialize((json as DynamicJsonObject).Dictionary);
And result will have the expected output.

Related

How to change the value of a StringBuilder Parsing through JArray

I have struggled to finish this task, please if anyone can give me a hint I would be so thankful.
My main task is to get data from database using (FOR JSON AUTO) which is working :)
select filed1, field2, field3 from table FOR JSON AUTO;
And then after connecting to Data base I use the StringBuilder() to build a Json Array of objects which is working :)
var jsonResult = new StringBuilder();
if(!r.HasRows)
{
jsonResult.Append("[]");
}
else
{
while(r.Read())
{
jsonResult.Append(r.GetValue(0).ToString());
}
// JArray array = JArray...
}
After that I am trying to change the value of filed1 for each object inside the Json Array
JArray array = JArray.Parse(jsonResult.ToString());
foreach (JObject obj in array.Children<JObject>())
{
foreach (JProperty singleProp in obj.Properties())
{
string name = singleProp.Name;
string value = singleProp.Value.ToString();
if(name.ToString() == "field1")
{
Int64 newID = 1234;
value = newID.ToString();
}
}
}
This is working but My BIG QUESTION is how can I get it changed inside the jsonResult?
You simply have to replace the value that you want to update. Since StringBuilder has a .Replace inbuilt method, you can implement that method.
`JArray arr = JArray.Parse(jsonResult.ToString());
foreach (JObject obj in arr.Children<JObject>())
{
foreach(JProperty singleProp in obj.Properties())
{
string name = singleProp.Name;
string value = singleProp.Value.ToString();
if (name.ToString().Equals("field1")) //good practice
{
Int64 newID = 1234;
jsonResult.Replace(value, newID.ToString());//replacing old value with new value and directly updates jsonResult
}
//not necesssary, explanation is given below
var jsonElement = JsonSerializer.Deserialize<JsonElement>(jsonResult.ToString());
result = JsonSerializer.Serialize(jsonElement, options);
}
}`
And for better formatting, I used JsonSerializer so that your output will look like json object rather than whole string without any lines.
` var options = new JsonSerializerOptions()
{
WriteIndented = true
};
var result = ""
while loop{
jsonResult.Append(r.GetValue(0).ToString());
(Above code)
}
`

How to concat values with same key from JSON Array

I'm working on a project where I want to build tokens from a JSON Array.
//Data fed to the system
{"Fruits":[{"Number":"111", "Name":"Apple"}, {"Number":"112", "Name":"Orange"},{"Number":"113", "Name":"Peach"}]}
//serializes the http content to a string
string result = Request.Content.ReadAsStringAsync().Result;
//deserializes result
Dictionary<string, dynamic> data = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(result);
//builds custom tokens
var customTokens = new Dictionary<string, object>();
foreach (var dataField in data)
{
if (dataField.Value is JArray)
{
string nameValue = "";
foreach (JObject content in dataField.Value.Children<JObject>())
{
foreach (JProperty prop in content.Properties())
{
nameValue += prop.Name.ToString() + " : " + prop.Value.ToString();
}
}
customTokens.Add($"{dataField.Key}", nameValue);
}
}
The above code managed to create token $Fruits.
But i also want to achieve token $Number and $Name, where values of each token is from the concatenated values of same key. Example, If I use the "$Number", it will be replaced by 111, 112, 113 and If I use the $Name, it will be replaced by Apple, Orange, Peach.
Also, I'm not using any strongly type models as I don't know what data will be fed to the system.
Any help?
There are a few minor changes to your code to achieve this. First make your dictionary look like this:
var customTokens = new Dictionary<string, List<string>>();
Then, when you loop over all the properties in the array, check if the property has been added, and if not add it.
foreach (JProperty prop in content.Properties())
{
if(customTokens.ContainsKey(prop.Name))
{
customTokens[prop.Name].Add(prop.Value.ToString());
}
else
{
customTokens.Add(prop.Name, new List<string> { prop.Value.ToString() });
}
}
At the end you have a dictionary where the key is the property name and the value is a List<string> - this can be concatenated together:
foreach(var item in customTokens)
{
Console.WriteLine(item.Key + ":" + String.Join(",", item.Value));
}
Or, if you really want it in a dictionary of concatenated strings just do this
var finalResult = customTokens.ToDictionary(k => k.Key, v => String.Format(",",v.Value));
Note you'll need to add using System.Linq to the top of your file to use ToDictionary
Final test code:
var result = "{ \"Fruits\":[{\"Number\":\"111\", \"Name\":\"Apple\"}, {\"Number\":\"112\", \"Name\":\"Orange\"},{\"Number\":\"113\", \"Name\":\"Peach\"}]}";
Dictionary<string, dynamic> data = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(result);
var customTokens = new Dictionary<string, List<string>>();
foreach (var dataField in data)
{
if (dataField.Value is JArray)
{
foreach (JObject content in dataField.Value.Children<JObject>())
{
foreach (JProperty prop in content.Properties())
{
if(customTokens.ContainsKey(prop.Name))
{
customTokens[prop.Name].Add(prop.Value.ToString());
}
else
{
customTokens.Add(prop.Name, new List<string> { prop.Value.ToString() });
}
}
}
foreach(var item in customTokens)
{
Console.WriteLine(item.Key + ":" + String.Join(",", item.Value));
}
}
}

Convert Variable Header to JSON JArray

I have code that gets data from JSON:
dynamic myJSON = Newtonsoft.Json.JsonConvert.DeserializeObject(sourceString);
foreach (var item in myJSON["data"]["results"])
{ ... }
Now, I'd like to make this part myJSON["data"]["results"] for versatile, ideally by passing in a variable such as:
dynamic myJSON = Newtonsoft.Json.JsonConvert.DeserializeObject(sourceString);
var variableResults = ((Newtonsoft.Json.Linq.JArray) string.Format("myJSON[\"{0}\"][\"{1}\"]", myData, myResults);
foreach (var item in variableResults)
{ ... }
I've tried different conversions, and looked here, but no question comes close, and the conversions always comes out string, not a JArray. Any ideas?
You can use JObject to parse it:
var json = "{asd: {qwe: [1,2,3,4]}}";
var obj = JObject.Parse(json);
// just plug in your variables here
var myData = "asd";
var myResult = "qwe";
var path = $"{myData}.{myResult}";
foreach (var item in obj.SelectToken(path).ToObject<int[]>())
{
// ...
}
My solution ended up being:
// User would use a textbox with space separated values like "data results"
var parameterList = textBox1.Text.Trim().Replace(" ", ".");
var jsonObject = JObject.Parse(sourceString);
var jsonList = jsonObject.SelectToken(parameterList);
if (jsonList == null) { ... }
foreach (var item in jsonList)
{ ... }

Deserialize json string to object in c# in Key value pair (Comma separated values)

I have below json in string as parameter to a WebMethod.
How can I deserialize in such a way that value comes in Key value pair.
Json String Parameter:
["Ref No,0","Date,0","Amt,0","Sender Name,0","Sender Add,0","Beneficiary Name,0","Beneficiary Add,0","Phone,0","Secret Code,0","Secret Ans,0","Preferred Id,0"]
WebMethod:
[System.Web.Services.WebMethod]
public static string SaveMappings(string mappingData)
{
//string str = "{\"Arg1\":\"Arg1Value\",\"Arg2\":\"Arg2Value\"}";
//JavaScriptSerializer serializer = new JavaScriptSerializer();
//object obj;
//var data = serializer.Deserialize(mappingData,);
var data = mappingData.ToArray();
if (data != null)
{
}
var d2 = mappingData.Split(',');
if (d2!=null)
{
}
return mappingData;
}
If you need to work with JSON data then use Newtonsoft.JSON library.
Convert the object to an array of strings and then split every line.
With this approach you can be sure that the given string is actually an JSON array and it is correct.
var str = "[\"Ref No,0\",\"Date,0\",\"Amt,0\",\"Sender Name,0\",\"Sender Add,0\",\"Beneficiary Name,0\",\"Beneficiary Add,0\",\"Phone,0\",\"Secret Code,0\",\"Secret Ans,0\",\"Preferred Id,0\"]";
string[] objs = JsonConvert.DeserializeObject<string[]>(str);
Dictionary<string, string> dic = new Dictionary<string, string>();
foreach (var obj in objs)
{
var keyValue = obj.Split(',');
dic.Add(keyValue[0], keyValue[1]);
}
foreach (var record in dic)
{
Console.WriteLine("{0} => {1}", record.Key, record.Value);
}
Or this one using LINQ. It looks better and it can be written faster. However, it is less optimal (two calls of Split instead of one).
public Dictionary<string, string> FromJsonArray(string jsonArray)
{
return JsonConvert.DeserializeObject<string[]>(jsonArray)
.ToDictionary(obj => obj.Split(',')[0], obj => obj.Split(',')[1]);
}
// ...
var str = "[\"Ref No,0\",\"Date,0\",\"Amt,0\",\"Sender Name,0\",\"Sender Add,0\",\"Beneficiary Name,0\",\"Beneficiary Add,0\",\"Phone,0\",\"Secret Code,0\",\"Secret Ans,0\",\"Preferred Id,0\"]";
foreach (var record in FromJsonArray(str))
{
Console.WriteLine("{0} => {1}", record.Key, record.Value);
}
why don't you just change every ',' in the string array to ':' then pass it to the method, from what you wrote in the question, this should work

How to convert json to NameValueCollection

How could you convert a string of JSON to a C# NameValueCollection simply, preferably without using a 3rd party parser?
I'm not sure why everyone is still recommending JSON.NET for deserialization of JSON. I wrote a blog post on how to deserialize JSON to C#.
In short, it's like this:
using System.Web.Script.Serialization;
var jss = new JavaScriptSerializer();
var dict = jss.Deserialize<Dictionary<string, string>>(jsonText);
NameValueCollection nvc = null;
if (dict != null) {
nvc = new NameValueCollection(dict.Count);
foreach (var k in dict) {
nvc.Add(k.Key, k.Value);
}
}
}
var json = jss.Serialize(dict);
Console.WriteLine(json);
Be sure to add a reference to System.Web.Extensions.dll.
Note:
I usually deserialize to dynamic, so I'm assuming that NameValueCollection would work. However, I haven't verified if it actually does.
EDIT
Pure .net solution without third party development have look : JavaScriptSerializer – Dictionary to JSON Serialization and Deserialization
make use of Json.NET
string jsonstring = #"{""keyabc"":""valueabc"",""keyxyz"":""valuexyz""}";
Dictionary<string, string> values =
JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonstring);
Check #jon answer suggest same : .Net Linq to JSON with Newtonsoft JSON library
If your JSON contains nested objects whithin it the solution below will handle them properly (based on JSON.NET, but you can adapt to the JSON parser of your choice).
This usage example:
var json = "{\"status\":\"paid\",\"date\":\"2019-10-09T17:30:51.479Z\",\"customer\":{\"id\":123456789,\"country\":\"br\",\"name\":\"Thomas Vilhena\",\"phone_numbers\":[\"+5511987654321\"],\"documents\":[{\"id\":\"doc_id\"}]}}";
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
var nvc = new NameValueCollection(dict.Count);
AddKeyValuePairs(nvc, dict);
Console.WriteLine(nvc["status"]);
Console.WriteLine(nvc["date"]);
Console.WriteLine(nvc["customer[phone_numbers][0]"]);
Console.WriteLine(nvc["customer[id]"]);
Console.WriteLine(nvc["customer[documents][0][id]"]);
Produces the following output:
paid
09.10.2019 17:30
+5511987654321
123456789
doc_id
And here's the implementation:
private static void AddKeyValuePairs(
NameValueCollection nvc,
Dictionary<string, object> dict,
string prefix = null)
{
foreach (var k in dict)
{
var key = prefix == null ? k.Key : prefix + "[" + k.Key + "]";
if (k.Value != null)
AddKeyValuePair(nvc, key, k.Value);
}
}
private static void AddKeyValuePair(
NameValueCollection nvc,
string key,
object value)
{
if (value is string || value.GetType().IsPrimitive)
{
nvc.Add(key, value.ToString());
}
else if (value is DateTime)
{
nvc.Add(key, ((DateTime)value).ToString("g"));
}
else
{
AddNonPrimitiveValue(nvc, key, value);
}
}
private static void AddNonPrimitiveValue(
NameValueCollection nvc,
string key,
object value)
{
var a = value as JArray;
if (a != null)
{
for (int i = 0; i < a.Count; i++)
AddKeyValuePair(nvc, key + "[" + i + "]", a[i]);
}
else
{
var v = value as JValue;
if (v != null)
{
AddKeyValuePair(nvc, key, v.Value);
}
else
{
var j = value as JObject;
if (j != null)
AddKeyValuePairs(nvc, j.ToObject<Dictionary<string, object>>(), key);
}
}
}

Categories

Resources