Serialize flat Dictionary into multi-sub-object JSON - c#

In C# I have a flat Dictionary<string, string> where keys are in form of obj1/obj2/obj3 and values are direct string. Now I want to serialize that into subobjects, so example values:
var dict = new Dictionary<string, string> { {"foo/bar/baz1", "123" }, {"foo/baz", "456" }, { "foo/abc", "def" } };
should result with:
{
"foo": {
"bar": {
"baz1": "123"
},
"baz": "456",
"abc": "def"
}
}
Optionally I want to remove quotes around "123" and "456" in output if they can be interpreted as numbers or booleans.
I am using Newtonsoft.JSON

You can parse a source dictionary into JObject using JObject.FromObject method. Then go through all of properties, split them using string.Split and parse recursively to a new JObject, representing a properties tree. Finally add this object to the destination one using JObject.Add, or update it if the given key is already exist
var dict = new Dictionary<string, string> { { "foo/bar/baz1", "123" }, { "foo/baz", "456" }, { "foo/abc", "def" } };
var source = JObject.FromObject(dict);
var dest = new JObject();
foreach (var property in source.Properties())
{
//split the name into parts
var items = property.Name.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
var item = items.FirstOrDefault();
if (string.IsNullOrEmpty(item))
continue;
//get JObject representing a properties tree
var result = WriteItems(items.Skip(1).ToList(), property.Value);
//check that destination already contains top property name (e.g. 'foo')
if (dest.ContainsKey(item))
{
(dest[item] as JObject)?.Add(result.First);
}
else
{
dest.Add(item, result);
}
}
Console.WriteLine(dest.ToString());
//local function to recursively go through all properties and create a result JObject
JObject WriteItems(IList<string> items, JToken value)
{
var item = items.FirstOrDefault();
items.RemoveAt(0);
if (!items.Any()) //no more items in keys, add the value
return new JObject(new JProperty(item, value));
return new JObject(new JProperty(item, WriteItems(items, value)));
}
It produces the following output
{
"foo": {
"bar": {
"baz1": "123"
},
"baz": "456",
"abc": "def"
}
}
Also, the code above allows you to handle a properties tree with any depth. I don't think that there is a built-in way to serialize the structure like foo/bar/baz1 into sub-objects in Json.NET

Related

How to throw an exception when member comes twice on Deserializing with JsonConvert

I have JSON which contains duplicated members:
[
{
"MyProperty": "MyProperty1",
"MyProperty": "MyWrongProperty1",
"MyProperty2": "MyProperty12",
"MyProperty2": "MyWrongProperty2"
},
{
"MyProperty": "MyProperty21",
"MyProperty2": "MyProperty22"
}
]
When I deserialize, it is getting the last property. Here is the code:
var myJson = File.ReadAllText("1.txt");
List<MyClass> myClasses = JsonConvert.DeserializeObject<List<MyClass>>(myJson);
But I need to throw an exception when JSON string contains duplicated properties. How can I do that?
You need to added DuplicatePropertyNameHandling = DuplicatePropertyNameHandling.Error in your JsonLoadSettings.
You can dig in details following this answer.
There is also a thread from Newtonsoft.json that cover this topic.
You can use JsonTextReader from Newtonsoft.Json to get all tokens which are of PropertyName and then probably use LINQ GroupBy() like
string json = "[
{
"MyProperty": "MyProperty1",
"MyProperty": "MyWrongProperty1",
"MyProperty2": "MyProperty12",
"MyProperty2": "MyWrongProperty2"
},
{
"MyProperty": "MyProperty21",
"MyProperty2": "MyProperty22"
}
]";
List<string> props = new List<string>();
JsonTextReader reader = new JsonTextReader(new StringReader(json));
while (reader.Read())
{
if (reader.Value != null && reader.TokenType == "PropertyName")
{
props.Add(reader.Value);
}
}
Now use GroupBy() on the list to see duplicates
var data = props.GroupBy(x => x).Select(x => new
{
PropName = x.Key,
Occurence = x.Count()
}).Where(y => y.Occurence > 1).ToList();
If (data.Any())
{
Throw New Exception("Duplicate Property Found");
}
JsonConvert.DeserializeObject had that functionality in a older version but they removed it.
To provide an alternative they added a new option to the JsonLoadSettings - DuplicatePropertyNameHandling - that allows you to set up the desired behaviour.
Here you go:
public object DeserializeObject(string json)
{
using (var stringReader = new StringReader(json))
using (var jsonReader = new JsonTextReader(stringReader))
{
return JToken.ReadFrom(jsonReader,
new JsonLoadSettings{ DuplicatePropertyNameHandling = DuplicatePropertyNameHandling.Error })
.ToObject<object>();
}
}

C# Deserialize string of multiple arrays with json-string in it explicit to List<string>

i have a json-string, or bit more something like a "string of arrays":
"[
{
"type":"radio-group",
"label":"Radio-Button-Gruppe",
"name":"radio-group-1556028993486",
"className":"iCheck",
"values":[
{
"label":"aaaaaaa",
"value":"aaaaaaa"
},
{
"label":"bbbbbbbbb",
"value":"bbbbbbbbb"
},
{
"label":"cccccccccccc",
"value":"cccccccccccc"
}
]
}
],
[
...
],
[
{
"type":"header",
"label":"Überschrift"
}
]"
Now I want to have a List<string> of each array in this string. Something like:
List<string> x[0] = "{
"type":"radio-group",
"label":"Radio-Button-Gruppe",
"name":"radio-group-1556028993486",
"className":"iCheck",
"values":[
{
"label":"aaaaaaa",
"value":"aaaaaaa"
},
{
"label":"bbbbbbbbb",
"value":"bbbbbbbbb"
},
{
"label":"cccccccccccc",
"value":"cccccccccccc"
}
]
}"
What's the best way to do that?
I already tried out JsonConvert.DeserializeObject<IEnumerable<string>>() but my problem is that he wants to deserialize my jsons to an object. But I want to keep them as a string und put them to my list.
Why I need a list of string for each array?
Because I use the json-strings inside the arrays to render a form. each array show you a page of the form, and the json is the data for rendering this form.
to render this form i have to go through a loop through all of this arrays and render the json in it for every page.
You can use JsonConvert.DeserializeObject<IEnumerable<JToken>>(json) where json is each of your top level arrays. Then you can iterate through the results and use .ToString() on each JToken object.
As others have pointed out, you don't have valid JSON, so I didn't try to give a solution to parse out the top level arrays.
var json = #"[
{
""type"":""radio-group"",
""label"":""Radio-Button-Gruppe"",
""name"":""radio-group-1556028993486"",
""className"":""iCheck"",
""values"":[
{
""label"":""aaaaaaa"",
""value"":""aaaaaaa""
},
{
""label"":""bbbbbbbbb"",
""value"":""bbbbbbbbb""
},
{
""label"":""cccccccccccc"",
""value"":""cccccccccccc""
}
]
}
]";
var arrays = new[] { json };
var objectsAsStrings = new List<string>();
foreach (var array in arrays)
{
var tokens = JsonConvert.DeserializeObject<IEnumerable<JToken>>(array);
foreach (var token in tokens)
{
objectsAsStrings.Add(token.ToString());
}
}
var json = "yourjson";
var jsonnew = "[" + json+ "]";
var list = JsonConvert.DeserializeObject<dynamic>(jsonnew);
var result = new List<string>();
foreach (var item in list)
{
var str = JsonConvert.SerializeObject(item);
result.Add(str);
}
You can use this , too.

Extracting variable data from JSON in C#

I have the following JSON which I need to manipulate into a different JSON format to be consumed by another process. My data is variable to some extent. Here is an example:
{
"subform_12": {
"multiline_2": "Subform 1 Long Text",
"listpicker_5": "High",
"alpha_1": "SubForm 1 Text"
},
"subform_13": {
"multiline_2": "Subform 2 Long Text",
"alpha_1": "SubForm 2 Text"
}
}
The variable part is the name of the json object (eg "subform_13") and the number and content of name pairs per object (eg "multiline_2": "Subform 1 Long Text").
What I need to do is convert each node into its own chunk of json, as in the following format:
{
"subform_13": [
[{
"fieldKey": "multiline_2",
"value": "Subform 2 Long Text"
},
{
"fieldKey": "alpha_1",
"value": "SubForm 2 Text"
}
]
]
}
Then separately:
{
"subform_13": [
[{
"fieldKey": "multiline_2",
"value": "Subform 2 Long Text"
},
{
"fieldKey": "alpha_1",
"value": "SubForm 2 Text"
}
]
]
}
So far I see that I can iterate thru the list as follows:
var json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(
jsonString,
new Newtonsoft.Json.JsonSerializerSettings()
{
DateParseHandling = Newtonsoft.Json.DateParseHandling.None,
});
foreach (var item in json)
{
// I can see the "subform_13" and contents here in item , how do I generically extract them?
}
Any help appreciated.
Here is your Main method augmented with the ability to iterate through all values:
static void Main(string[] args)
{
var json = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string,JObject>>(
jsonString,
new Newtonsoft.Json.JsonSerializerSettings()
{
DateParseHandling = Newtonsoft.Json.DateParseHandling.None,
});
foreach (var item in json)
{
var key = item.Key; // "subform_12"
var val = item.Value;
Console.WriteLine(key+":");
foreach (var field in val)
{
var fieldKey = field.Key; // e.g. "multiline_2"
var fieldVal = field.Value; // e.g. "Subform 1 Long Text"
Console.WriteLine($"{fieldKey}={fieldVal.Value<string>()}");
}
Console.WriteLine();
}
}
I am just printing the values out; you would construct your new objects - for example as dynamic - using these values.
The output of my Main is:
subform_12:
multiline_2=Subform 1 Long Text
listpicker_5=High
alpha_1=SubForm 1 Text
subform_13:
multiline_2=Subform 2 Long Text
alpha_1=SubForm 2 Text
Hope it helps.
There are probably more elegant ways using linq, but here's code using a plain old JavaScriptSerializer from System.Web.Extensions.
There is a result dictionary, which you probably don't need if you want each object separated.
The json strings for each object is stored in the allJson list.
Similary, if you want the dictionary objects themselves you could just add seperated to a list during each iteration.
string s = "{\"subform_12\":{\"multiline_2\":\"Subform 1 Long Text\",\"listpicker_5\":\"High\",\"alpha_1\":\"SubForm 1 Text\"},\"subform_13\":{\"multiline_2\":\"Subform 2 Long Text\",\"alpha_1\":\"SubForm 2 Text\"}}";
JavaScriptSerializer ser = new JavaScriptSerializer();
Dictionary<string, object> obj = ser.DeserializeObject(s) as Dictionary<string, object>;
// combined dictionary of all results
Dictionary<string, object> result = new Dictionary<string, object>();
// an intermediary dictionary to house the results of each object
Dictionary<string, object> separated = new Dictionary<string, object>();
// a list to hold the json representation of each separate object
List<String> allJson = new List<string>();
foreach (KeyValuePair<string, object> src in obj)
{
Dictionary<string, object> children = (Dictionary<string, object>)src.Value;
Dictionary<string, object> t = new Dictionary<string, object>();
separated = new Dictionary<string, object>();
List<object> l = new List<object>();
foreach (KeyValuePair<string, object> child in children)
{
t.Add("fieldKey", child.Key);
t.Add("value", child.Value);
l.Add(t);
t = new Dictionary<string, object>();
}
separated.Add(src.Key, l.ToArray());
allJson.Add(ser.Serialize(separated));
result.Add(src.Key, l.ToArray());
}
// final string containing all transformed objects combined.
string combined = ser.Serialize(result);

Creating JSON from a CSV file in C#

First of all my apologies because this is going to be a "How to" question rather than a technical question. I have a CSV file as follows-
London,Dubai,4
Dubai,Mumbai,8
Dubai,Dhaka,4
Now my plan is to create a JSON object from that CSV in the following format-
[
{
"From": "London",
"To": "Dubai",
"Duration": 4
},
{
"From": "Dubai",
"To": "Mumbai",
"Duration": 8
},
{
"From": "Dubai",
"To": "Dhaka",
"Duration": 4
},
]
How do I go about and do that? Currently I can load the CSV using OpenFileDialog but no idea what else I should do to get it done? Use Model Classes? JSON.Net? Please advice me and some code samples would be appreciated!
You can add csv records to a List<T> and then serialize it with Newtonsoft.Json to get your required JSON object. See the example below:
class Program
{
static void Main(string[] args)
{
string[] csv = new[] { "London,Dubai,4", "Dubai,Mumbai,8", "Dubai,Dhaka,4" };
List<model> list = new List<model>();
foreach (var item in csv)
{
string[] fields = item.Split(',');
list.Add(new model
{
From = fields[0],
To = fields[1],
Duration = fields[2]
});
}
var json = JsonConvert.SerializeObject(list);
Console.WriteLine(json);
Console.ReadLine();
}
}
public class model
{
public string From { get; set; }
public string To { get; set; }
public string Duration { get; set; }
}
You can use TextFieldParser from the Microsoft.VisualBasic.FileIO namespace and Microsoft.VisualBasic.dll assembly to parse CSV files. Despite the VisualBasic name the class is perfectly usable in c#.
First, add the following extension method:
public static class TextFieldParserExtensions
{
public static IEnumerable<string []> ReadAllFields(this TextFieldParser parser)
{
if (parser == null)
throw new ArgumentNullException();
while (!parser.EndOfData)
yield return parser.ReadFields();
}
}
Now you can use LINQ to transform each CSV line into an anonymous or named type for serialization, like so:
var csv = #"London,Dubai,4
Dubai,Mumbai,8
Dubai,Dhaka,4";
string json;
using (var stream = new StringReader(csv))
using (TextFieldParser parser = new TextFieldParser(stream))
{
parser.SetDelimiters(new string[] { "," });
var query = parser.ReadAllFields()
.Select(a => new { From = a[0], To = a[1], Duration = int.Parse(a[2]) });
json = new JavaScriptSerializer().Serialize(query);
}
Here I am using JavaScriptSerializer but the same code can be used with json.net
json = JsonConvert.SerializeObject(query, Formatting.Indented);
Be sure to evaluate the query before closing the TextFieldParser.
I Believe this should work for all different kinds of .csv files
Comments are in the code
public class Program
{
public static void Main(string[] args)
{
var list = new List<Dictionary<string, string>>();
Console.WriteLine("Put in the path to your .csv file");
var response1 = Console.ReadLine();
Console.WriteLine("Initializing...");
// Read All of the lines in the .csv file
var csvFile = File.ReadAllLines(response1);
// Get The First Row and Make Those You Field Names
var fieldNamesArray = csvFile.First().Split(',');
// Get The Amount Of Columns In The .csv
// Do the -1 so you can use it for the indexer below
var fieldNamesIndex = fieldNamesArray.Count() - 1;
// Skip The First Row And Create An IEnumerable Without The Field Names
var csvValues = csvFile.Skip(1);
// Iterate Through All Of The Records
foreach (var item in csvValues)
{
var newDiction = new Dictionary<string, string>();
for (int i = 0; i < fieldNamesIndex;)
{
foreach (var field in item.Split(','))
{
// Think Of It Like This
// Each Record Is Technically A List Of Dictionary<string, string>
// Because When You Split(',') you have a string[]
// Then you iterate through that string[]
// So there is your value but now you need the field name to show up
// That is where the Index will come into play demonstrated below
// The Index starting at 0 is why I did the -1 on the fieldNamesIndex variable above
// Because technically if you count the fields below its actually 6 elements
//
// 0,1,2,3,4,5 These Are The Field Names
// 0,1,2,3,4,5 These Are The Values
// 0,1,2,3,4,5
//
// So what this is doing is int i is starting at 0 for each record
// As long as i is less than fieldNamesIndex
// Then split the record so you have all of the values
// i is used to find the fieldName in the fieldNamesArray
// Add that to the Dictionary
// Then i is incremented by 1
// Add that Dictionary to the list once all of the values have been added to the dictionary
//
// Add the field name at the specified index and the field value
newDiction.Add(fieldNamesArray.ElementAt(i++), field);
}
list.Add(newDiction);
}
}
Console.WriteLine("Would You Like To Convert To Json Now?");
Console.WriteLine("[y] or [n]");
var response = Console.ReadLine();
if (response == "y")
{
Console.WriteLine("Where Do You Want The New File?");
var response2 = Console.ReadLine();
// Serialize the list into your Json
var json = JsonConvert.SerializeObject(list);
File.Create(response2).Dispose();
File.AppendAllText(response2, json);
Console.WriteLine(json);
Console.ReadLine();
}
else
{
Console.WriteLine("Ok See You Later");
Console.ReadLine();
}
}
}

Get values and keys in json object using Json.Net C#

Hi there I have json that looks like this:
{
"Id": " 357342524563456678",
"title": "Person",
"language": "eng",
"questionAnswer": [
{
"4534538254745646.1": {
"firstName": "Janet",
"questionNumber": "1.1"
}
}
]
}
Now I have written some code that loops over the objects in the questionAnswer array and then gets the name of the object which is 4534538254745646.1. Now Im trying to save the key of each Item and the value aswell but I am only managing to get the value.
How would I do this, here is my code:
JToken entireJson = JToken.Parse(json);
JArray inner = entireJson["questionAnswer"].Value<JArray>();
foreach(var item in inner)
{
JProperty questionAnswerDetails = item.First.Value<JProperty>();
//This line gets the name, which is fine
var questionAnswerSchemaReference = questionAnswerDetails.Name;
var properties = questionAnswerDetails.Value.First;
//This only gets Janet
var key = properties.First;
var value = properties.Last;
}
So at the moment Im only able to get Janet, But I also want the firstname field. I want to then take this and add to a dictionary i.e.
Dictionary<string, string> details = new Dictionary<string, string>();
//suedo
foreach(var item in questionAnswerObjects)
details.Add(firstName, Janet);
//And then any other things found below this
So Here is he complete code that gets the keys and values for each item in the object in the array:
string key = null;
string value = null;
foreach(var item in inner)
{
JProperty questionAnswerDetails = item.First.Value<JProperty>();
var questionAnswerSchemaReference = questionAnswerDetails.Name;
var propertyList = (JObject)item[questionAnswerSchemaReference];
questionDetails = new Dictionary<string, object>();
foreach (var property in propertyList)
{
key = property.Key;
value = property.Value.ToString();
}
questionDetails.Add(key, value);
}
I can now add key and value to the dictionary

Categories

Resources