Using JSON.NET to access JSON attributes to create a C# dictionary - c#

I want to convert what is ultimately a dictionary in JSON to a C# dictionary without much ado.
Am I barking up the wrong tree by using the JSON.NET library here? The JArray class doesn't want to give me anything to access the attribute (only the value) ie it tells me the value but never the "key".
I can't quite believe no one else would find this limiting, so am assuming I'm missing something. My muddled attempt is this:
Given this json:
{
"appSettings" : [
{"rows": "5"},
{"columns" : "7"}
]
}
I would like to select this into a dictionary like this:
var dict = jsonObject["appSettings"].Select(s => new
{
key = s.Name, // wish this property existed
value = s.Value // wish this property existed
}).ToDictionary(s => s.key, s => s.value);
This is my UnitTest:
[Test]
public void CanLoadJsonAppSettings()
{
var json = #"
""{appSettings"" : [
{""ViewRows"" : ""1""},
{""ViewColumns"" : ""2""}
]}";
var dict = CreateJsonDictionary(json);
Assert.That(dict.Count, Is.EqualTo(2));
}
public CreateJsonDictionary(string jsonText)
{
var jsonObject = JObject.Parse(jsonText);
return jsonObject["appSettings"].Select(s => new
{
key = s.Name,
value = s.Value
}).ToDictionary(s => s.key, s => s.value);
}
EDIT: Thanks to #jim, we are a little closer.
For completeness, I will document the slightly awkward step I needed in order to get at the object I needed:
I had to change my JSON.
Instead of using an array (as in the code above) I used a more simple/truer dictionary:
var json = #"
{
""appSettings"" : {
""ViewRows"" : ""1"",
""ViewColumns"" : ""2""
}
}";
Then I had to Parse, get a JSON JObject, then convert back to a string, and then Deserialize:
var jo = JObject.Parse(jsonText);
var appSettings = jo["appSettings"];
var appSettings = JsonConvert.DeserializeObject<Dictionary<string, string>>(appSettings.ToString());
So part of my problem, was getting JSON confused.
Even so, if there is a more elegant way to do this, I'm all ears.
EDIT2: I still had to solve the original problem above, converting a JSON array to a dictionary. Once my JSON is corrected to contain proper name/value pairs:
"connectionStrings": [
{"name" : "string1", "value" : "value1"},
{"name" : "string2", "value" :"value2"},
]
This is the code that solved it (nb it looks a lot like my original attempt):
var jsonObj = JObject.Parse(jsonText);
var conStrings = jsonObj.Properties().Select(s =>
new {
key = s.Name,
value = s.Value.ToString()
}).ToDictionary(s => s.key, s => s.value);
And this only works if you have no other arrays.

Panda,
Verbatim from james newton king himself on SO to a similar question:
// Json.NET does this...
string json = #"{""key1"":""value1"",""key2"":""value2""}";
Dictionary<string, string> values
= JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
you can find the thread here:
How can I deserialize JSON to a simple Dictionary<string,string> in ASP.NET?
hope this helps (tho not 100% certain on how this works with complex tree structures)

This is the MS way to do this, but it's quite complex and I really think than YvesR's solution might be easier to implement.
http://atsung.wordpress.com/2008/08/07/javascriptserializer-example/

To convert js assosiative array into dictionary, use may use converter which is as follows:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace MyJsonConverters
{
public class AssosiativeArrayConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.GetInterface(typeof(IDictionary<,>).Name) != null;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
var result = Activator.CreateInstance(objectType);
var addMethod = result.GetType().GetMethod("Add");
var dictionaryTypes = objectType.GetGenericArguments();
foreach (JProperty property in jObject.Properties())
{
var key = Convert.ChangeType(property.Name, dictionaryTypes[0]);
var value = serializer.Deserialize(property.Value.CreateReader(), dictionaryTypes[1]);
addMethod.Invoke(result, new[] { key, value });
}
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
}
then usage is as follows:
Dictionary<string, string> dictionary;
dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(value, new AssosiativeArrayConverter);
where T is your Dictionary e.g. Dictionary or whatever you like.
Json which is deserialized in my case looks like follows:
{
"MyDictionary": {
"key1": [
"value1",
"value2",
"value3"
],
"key2": [ ]
}

I know it is not a proper answer direct to your question, but for all JSON stuff in C# here is the link for the a very good library you can use to easy do anything with JSON in C#.
http://james.newtonking.com/pages/json-net.aspx

Related

Newtonsoft - How to parse an array of objects

I just want to get this JSON into some kind of object. JArray and JToken are completely confusing to me.
I can create a class so that Newtonsoft knows what to map to but if you will notice the objects have the structure of: { "anAnimal": { foo: 1, bar: 2 }} and I don't know what that mapper object will look like. I'm pretty sure this should just work instantly with zero thought on my part.
var myFavoriteAnimalsJson = #"
[
{
""Dog"": {
""cuteness"": ""7.123"",
""usefulness"": ""5.2"",
}
},
{
""Cat"": {
""cuteness"": ""8.3"",
""usefulness"": ""0"",
}
}
]";
var jArray = new JArray(myFavoriteAnimalsJson);
// grab the dog object. or the cat object. HOW CUTE IS THE DOG?
With .SelectToken() to construct the JSON path query logic.
The below sample to query the first item of animals to get the object of "Dog" token and its value.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
JArray animals = JArray.Parse(myFavoriteAnimalsJson);
var dog = animals[0].SelectToken("Dog");
Console.WriteLine(dog);
Console.WriteLine(dog["cuteness"]);
Sample Program
Output
{
"cuteness": "7.123",
"usefulness": "5.2"
}
7.123
You can deserialize it to a List<Dictionary<string, AnimalData>>
class AnimalData
{
public decimal cuteness;
public decimal usefulness;
}
var myFavoriteAnimalsJson = #"
[
{
""Dog"": {
""cuteness"": ""7.123"",
""usefulness"": ""5.2"",
}
},
{
""Cat"": {
""cuteness"": ""8.3"",
""usefulness"": ""0"",
}
}
]";
var results = JsonConvert.DeserializeObject<List<Dictionary<string, AnimalData>>>(myFavoriteAnimalsJson);
Now each list item contains a dictionary with a single key of Dog Cat...
If you start from a serialized JSON, i.e. a string, you have to parse it:
var jArray = JArray.Parse(myFavoriteAnimalsJson);

How to address an object from a json array

Using the JSON library, I've imported an array of objects:
dynamic serviceList = JsonConvert.DeserializeObject(listString)
I've got an array of json objects, each has the property "name".
[
{
"name":"abcd",
"properties":{
"type":"1234"
}
},
{
"name":"xyz",
"properties":{
"type":"aaaa"
}
}
]
How do I address just the object "abcd"?
You can parse your json Array using Newtonsoft.Json JArray.Parse() function.
Use FirstOrDefault() to get record where name is "abcd"
string listString = #"[{'name': 'abcd','properties': {'type': '1234'}},{'name': 'xyz', 'properties': { 'type': 'aaaa'}}]";
JArray jArray = JArray.Parse(listString);
//FirstOrDefault to get first record which satisfy the condition
var result = jArray.FirstOrDefault(x => (string)x["name"] == "abcd");
Console.WriteLine(result);
Output:
{
"name": "abcd",
"properties": {
"type": "1234"
}
}
.Net Fiddle
The right way to solve the problem is create a static Object
Public Obj1 {
public string name {get;set;}
public Properties properties {get;set;}
}
Public Properties {
public string type {get;set;}
}
Then you can deserialize the JSON into a List<Obj1>, in this way you can iterate your list and find the "name":"abcd" Object. var myobj = mylist.FirstOrDefault(x=> x.name == "abcd")
You can use the dynamic to do pretty much anything you would like it to do, so nothing would stop you from evaluating your result in the following way:
dynamic selectionList = JsonConvert.DeserializeObject( json );
foreach (var item in selectionList) {
if ( string.Equals( (string)item.name, "abcd", StringComparison.OrdinalIgnoreCase ) ) {
Console.WriteLine( item );
}
}
This would work as per your original request, but I think you are making it a lot harder on yourself than need be :)
To see how this works, you could check this dotnetfiddle
I would probably create a class based on the spec, but I am assuming that properties is a dynamic list of properties and their values, meaning you would still end up with a Dictionary<string, object> in the end
You can access it like this:
for (int i = 0; i < serviceList.Count; i++)
{
if (serviceList[i].name == "abc")
{
DoSomethingWith(serviceList[i];
break;
}
}
Edit: didn't see that you wanted the "abc" element, so modified the code accordingly.
This will get the value for you as a JObject, from which you can access the contained values:
var serviceList = JArray.Parse(listString);
var target = serviceList.Single(s => s["name"].ToString() == "abcd");
if (target != null)
{
var type = target["properties"]["type"];
// etc
}

simple json retrieval

I know this is an old chestnut but I want to do this without importing newton-soft or json.net
I know this should work
this is the json :
{ "do": "Thing", "with": "abc" }
literally that's it. I need to get this into c# land
this is what I have so far
var json = wc.DownloadString("url");
Console.WriteLine("GOT >> " + json); //says GOT >> { "do": "Thing", "with": "abc" }
var sJson = new JavaScriptSerializer();
var data = sJson.Deserialize<Dictionary<string, string>[]>(json); //crashes with No parameterless constructor defined for type of 'System.Collections.Generic.Dictionary
what is the leanest least bloated way possible way that I can get data["do"] and data["with"] from my single line json? It will only ever return one thing ... if I have to string walk it I will but it shouldn't be this hard
You can create a backing class for the data
public class Data {
public string do { get; set; }
public string with { get; set; }
}
and simply desrialize to that
var data = sJson.Deserialize<Data>(json);
If the provided data is in fact an array then update the generic return type accordingly
There's no array in your JSON, just a simple object so it can be deserialized to a single Dictionary instance. Simply change Dictionary<string, string>[] to Dictionary<string, string>. Like this:
var data = sJson.Deserialize<Dictionary<string, string>>(json);
You can then access your values like this:
data["do"] // returns "Thing"
data["with"] // returns "abc"
The array is the problem. Try this (Try it Online!):
var json = "{ \"do\": \"Thing\", \"with\": \"abc\" }";
var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
Console.WriteLine(data["do"]);
Console.WriteLine(data["with"]);
output
Thing
abc
Note that I am using Json.NET here as written in the documentation:
Json.NET should be used for serialization and deserialization. Provides serialization and deserialization functionality for AJAX-enabled applications.
source
You can use Regex :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input = "{ \"do\": \"Thing\", \"with\": \"abc\" }";
string pattern = "\"(?'key'[^\"]+)\":\\s+\"(?'value'[^\"]+)";
MatchCollection matches = Regex.Matches(input, pattern);
Dictionary<string, string> dict = matches.Cast<Match>()
.GroupBy(x => x.Groups["key"].Value, y => y.Groups["value"].Value)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}

Json.net deserialising to objects from JSon that may contain either an array, or a nested array

I have a number of JSon files that I'm deserialising using
JsonSerializer serializer = new JsonSerializer();
t obj = (t)serializer.Deserialize(file, typeof(t));
to a collection of objects. They contain, amongst other things the following data. The number of arrays in "truthtable" is determined by the value of "gates"
"gates" : 1,
"truthtable" : [ false, true ]
and
"gates" : 2,
"truthtable" : [ [ false, false ], [ false, true ] ]
if I try to deserialise "truthtable" to the following property, example 1 fails.
public List<List<bool>>truthtable { get; set; }
Is there any way I can deserialise these two different types of truthtable to the same object? I've tried building a custom deserialiser, but Json sees both as "JsonToken.StartArray", so can't differentiate that way.
Ideally, I'd like to be able to deserialise both examples as if they were arrays of arrays of booleans.
Edit
Should have mentioned, I cannot alter the way the Json files are created. I don't have access to their creation.
This problem can be solved using a custom JsonConverter. The converter can read the number of gates and then populate the List<List<bool>> accordingly. If there is only one gate, it can wrap the single list in an outer list to make it work with your class.
Assuming the class that you are trying to deserialize into looks something like this:
class Chip
{
public int Gates { get; set; }
public List<List<bool>> TruthTable { get; set; }
}
then the converter might look something like this:
class ChipConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Chip));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
Chip chip = new Chip();
chip.Gates = (int)jo["gates"];
JArray ja = (JArray)jo["truthtable"];
if (chip.Gates == 1)
{
chip.TruthTable = new List<List<bool>>();
chip.TruthTable.Add(ja.ToObject<List<bool>>());
}
else
{
chip.TruthTable = ja.ToObject<List<List<bool>>>();
}
return chip;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use the converter, create an instance and add it to the serializer's Converters collection before you deserialize:
serializer.Converters.Add(new ChipConverter());
Or if you prefer, you can annotate your class with a [JsonConverter] attribute instead:
[JsonConverter(typeof(ChipConverter))]
class Chip
{
...
}
Here's a demo showing the converter in action (note I used JsonConvert.DeserializeObject<T>() here instead of creating a JsonSerializer instance, but it works the same way):
class Program
{
static void Main(string[] args)
{
string json = #"
[
{
""gates"": 1,
""truthtable"": [ false, true ]
},
{
""gates"": 2,
""truthtable"": [ [ false, false ], [ false, true ] ]
}
]";
List<Chip> chips = JsonConvert.DeserializeObject<List<Chip>>(json,
new ChipConverter());
foreach (Chip c in chips)
{
Console.WriteLine("gates: " + c.Gates);
foreach (List<bool> list in c.TruthTable)
{
Console.WriteLine(string.Join(", ",
list.Select(b => b.ToString()).ToArray()));
}
Console.WriteLine();
}
}
}
Output:
gates: 1
False, True
gates: 2
False, False
False, True
Simple... change the method who generates truthtable (in case of gate == 1) to output array of array (or List>).
"gates" : 1,
"truthtable" : [[ false,true ]]
Keep in mind, you have a type in your data contract,in this case the data contract expects an List> and you sent a wrong type (List<>). Can you wrote the code who generated "truthtable" in gate == 1 case?
PS. Sorry,i don´t speak english very well... =)
Assuming you're using .NET 4.0 or above, you can deserialize the json into a Dynamic Object
string jsonData = ....; // fill your json data here
dynamic d = JsonConvert.DeserializeObject(jsonData);
then check the type of d.truthtable[0] and determine what to do when d.truthtable is an array or a nested array
if (d.truthtable != null && d.truthtable.Count > 0)
{
if (d.truthtable[0].GetType() == typeof(Newtonsoft.Json.Linq.JValue))
{
// do something when truthtable is an array
}
else if (d.truthtable[0].GetType() == typeof(Newtonsoft.Json.Linq.JArray))
{
// do something when truthtable is a nested array
}
}
I´m assuming, this is a data contract conflict, and i´m suggest a workarrond... only think in performance...
In that case, is not elegant but, you can change the type in a easy way and force truthtable to be Array>..
String json = ...
int idx = 0;
while (idx >-1)
{
idx = json.Trim().IndexOf("\"truthtable\":[",idx);
if (idx >-1 && json[idx + 15] != '[')
{
idx += 14;
json = json.Insert(idx, "[");
json = json.Insert(json.IndexOf("]", idx),"]");
}
}
This help you??

Deserialize JSON string to Dictionary<string,object>

I have this string:
[{ "processLevel" : "1" , "segments" : [{ "min" : "0", "max" : "600" }] }]
I'm deserializing the object:
object json = jsonSerializer.DeserializeObject(jsonString);
The object looks like:
object[0] = Key: "processLevel", Value: "1"
object[1] = Key: "segments", Value: ...
And trying to create a dictionary:
Dictionary<string, object> dic = json as Dictionary<string, object>;
but dic gets null.
What can be the issue ?
See mridula's answer for why you are getting null. But if you want to directly convert the json string to dictionary you can try following code snippet.
Dictionary<string, object> values =
JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
I like this method:
using Newtonsoft.Json.Linq;
//jsonString is your JSON-formatted string
JObject jsonObj = JObject.Parse(jsonString);
Dictionary<string, string> dictObj = jsonObj.ToObject<Dictionary<string, object>>();
You can now access anything you want using the dictObj as a dictionary. You can also use Dictionary<string, string> if you prefer to get the values as strings.
The MSDN documentation for the as keyword states that the statement expression as type is equivalent to the statement expression is type ? (type)expression : (type)null. If you run json.GetType() it will return System.Object[] and not System.Collections.Generic.Dictionary.
In cases like these where the type of object into which I want to deserialize a json object is complex, I use an API like Json.NET. You can write your own deserializer as:
class DictionaryConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
Throw(new NotImplementedException());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Your code to deserialize the json into a dictionary object.
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Throw(new NotImplementedException());
}
}
And then you can use this serializer to read the json into your dictionary object. Here's an example.
I had the same problem and found a solution to it
Very simple
No bugs
Tested on operational product
Step 1) Create a generic class with 2 property
public class CustomDictionary<T1,T2> where T1:class where T2:class
{
public T1 Key { get; set; }
public T2 Value { get; set; }
}
Step 2) Create New class and inherit from first class
public class SectionDictionary: CustomDictionary<FirstPageSectionModel, List<FirstPageContent>>
{
}
Step 3) Replace Dictionary and List
public Dictionary<FirstPageSectionModel, List<FirstPageContent>> Sections { get; set; }
and
public List<SectionDictionary> Sections { get; set; }
Step 4) Serialize or Deserialize easely
{
firstPageFinal.Sections.Add(new SectionDictionary { Key= section,Value= contents });
var str = JsonConvert.SerializeObject(firstPageFinal);
var obj = JsonConvert.DeserializeObject<FirstPageByPlatformFinalV2>(str);
}
Thanks a lot
The problem is that the object is not of type Dictionary<string,object> or a compatible type, thus you can't cast directly. I would create a custom object and use Deserialize.
public class DeserializedObject{
public string processLevel{get;set;}
public object segments{get;set}
}
IEnumerable<DeserializedObject> object=jsonSerializer.Deserialize<IEnumerable<DeserializedObject>>(json);

Categories