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());
}
}
}
Related
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);
I've read a few posts on how to do this, but everything that i've seen the JSON object has specific property names to query, where i do not.
Here is my JSON string:
{
"424406": true,
"425171": true,
"411961": true
}
I want to loop through the array and read the string and bool field in separately (the JSON string is stored in a hidden variable, then accessed in my asp.net code behind):
dynamic dynObj = JsonConvert.DeserializeObject(partDetailsSelectedItems.Value);
foreach (dynamic x in dynObj)
{
string Id = ????
bool boolValue = ???
}
how do i get each of the 2 objects in "x" without specifying the name?
Ideally, i'd like to convert this stringified JSON into a generic list
List<string,bool>
but i need to understand how to handle my above scenario.
If you use LINQ to JSON it's simple, because JObject allows you to iterate over all the key/value pairs - it implements IEnumerable<KeyValuePair<string, JToken>>:
using System;
using System.IO;
using Newtonsoft.Json.Linq;
class Test
{
public static void Main(string[] args)
{
string text = File.ReadAllText("test.json");
var json = JObject.Parse(text);
foreach (var pair in json)
{
string id = pair.Key;
bool value = (bool) pair.Value;
Console.WriteLine("id: {0}; value: {1}", id, value);
}
}
}
The cast for the value is calling the explicit conversion from JToken to bool. No need for dynamic here at all.
Alternatively, as noted in comments, you can just deserialize to a Dictionary<string, bool>:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
class Test
{
public static void Main(string[] args)
{
string text = File.ReadAllText("test.json");
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, bool>>(text);
foreach (var pair in dictionary)
{
string id = pair.Key;
bool value = pair.Value;
Console.WriteLine("id: {0}; value: {1}", id, value);
}
}
}
I usually end up using LINQ to JSON myself, but either approach works and which is better depends on your context.
this is the JSON I have
{
"productNum":6,
"01":
{"US_7":"pna886377847444","US_7_5":"pna886377847529","US_8":"pna886377847604","US_8_5":"pna886377847666","US_9":"pna886377847741","US_9_5":"pna886377847826","US_10":"pna886377847895","US_10_5":"pna886377847987","US_11":"pna886377848069","US_11_5":"pna886377848144","US_12":"pna886377848229","US_13":"pna886377848328","US_14":"pna886377848427"},
"02":
{"US_7":"pna886377849103","US_7_5":"pna886377849202","US_8":"pna886377849295","US_8_5":"pna886377849394","US_9":"pna886377849493","US_9_5":"pna886377849592","US_10":"pna886377849660","US_10_5":"pna886377849745","US_11":"pna886377849820","US_11_5":"pna886377849905","US_12":"pna886377849981","US_13":"pna886377850086","US_14":"pna886377850185"}
}
A better view of the data:
What class should I describe to parse it ?
Looks like you can't turn this into a class because 02 is not a valid property name.
You can try using JObject that comes with Json.Net. It acts much like a Dictionary:
Here's a sample:
[Test]
public void Parse()
{
const string src = #"{
""productNum"":6,
""01"":
{""US_7"":""pna886377847444"",""US_7_5"":""pna886377847529"",""US_8"":""pna886377847604"",""US_8_5"":""pna886377847666"",""US_9"":""pna886377847741"",""US_9_5"":""p na886377847826"",""US_10"":""pna886377847895"",""US_10_5"":""pna886377847987"",""US_11"":""pna886377848069"",""US_11_5"":""pna886377848144"",""US_12"":""pna88637784 8229"",""US_13"":""pna886377848328"",""US_14"":""pna886377848427""},
""02"":
{""US_7"":""pna886377849103"",""US_7_5"":""pna886377849202"",""US_8"":""pna886377849295"",""US_8_5"":""pna886377849394"",""US_9"":""pna886377849493"",""US_9_5"":""p na886377849592"",""US_10"":""pna886377849660"",""US_10_5"":""pna886377849745"",""US_11"":""pna886377849820"",""US_11_5"":""pna886377849905"",""US_12"":""pna88637784 9981"",""US_13"":""pna886377850086"",""US_14"":""pna886377850185""}
}";
// filtering out the "productNum:6"
var dest =
JsonConvert.DeserializeObject<IDictionary<string, object>>(src)
.Where(x => x.Value.GetType() == typeof (JObject));
foreach (var item in dest)
{
var obj = (JObject) item.Value;
Console.WriteLine(item.Key);
foreach (var d in obj)
{
Console.WriteLine("{0}: {1}", d.Key, d.Value);
}
}
}
Use json.Net - http://james.newtonking.com/pages/json-net.aspx
Beyond that your question is too general. There are many ways you can go about doing it. The simple approach is to make a class, call it Product it's definition would something like;
public class Product
{
int productNum;
InnerData one;
InnerData two;
}
Before you serialize, rewrite the 01 and 02 to be one and two. InnerData should look something like;
public class InnerData
{
string US_1;
string US_2;
// rest of US_x fields
}
Then you can use the deserialize method - http://james.newtonking.com/projects/json/help/index.html?topic=html/SerializingJSON.htm
Product prod1 = jsonConvert.Deserialize<Product>(jsonString);
Found a solution myself:
string jString = File.ReadAllText(#"C:\_junk\funkyJSON.txt");
var deserializer = new JavaScriptSerializer();
var result = deserializer.DeserializeObject(jString);
var mapDyn = result as Dictionary<string, object>;
var valueSize = ((Dictionary<string, object>)mapDyn["01"])["US_7"].ToString();
Using .Net 4.5's DataContractSerializer, you can give a JSON element any variable name, while specifying its actual name with the "Name" attribute.
So your class could look like:
[DataContract]
public class MyData
{
[DataMember(Name="01")]
string Var1;
...
}
http://msdn.microsoft.com/en-us/library/bb412179.aspx
I am trying to serialize objects with the library ServiceStack.Text . This works
using System.Dynamic;
using ServiceStack.Text;
var x = new {Value= 10, Product = "Apples"};
Console.WriteLine(JsonSerializer.SerializeToString(x));
I get, as I expect
{"Value":10,"Product":"Apples"}
However
dynamic x = new ExpandoObject();
x.Value = 100;
x.Product = "Apples";
Console.WriteLine(JsonSerializer.SerializeToString(x));
I get to my surprise
[{"Key":"Value","Value":100},{"Key":"Product","Value":"Apples"}]
Why! What's going on?
Secondly, how can I get what I want?
ExpandoObject implements IConnection<KeyValuePair> and IEnumerable<KeyValuePair>:
public sealed class ExpandoObject :
IDynamicMetaObjectProvider,
IDictionary<string, object>,
ICollection<KeyValuePair<string, object>>,
IEnumerable<KeyValuePair<string, object>>,
IEnumerable, INotifyPropertyChanged
My guess is that internally, the ServiceStack serializer is treating the ExpandoObject as an IEnumerable<KeyValuePair>, and so it serializes to a JSON array of key/value pairs.
This differs from your first (working) code snippet because .NET actually builds a real (anonymous) class for your data, basically it makes:
public class SomeNameTheCompilerMakesUp {
internal int Value { get; set; }
internal string Product { get; set; }
}
for you automatically, so when it is sent to the serializer, it is working with a real class with real properties, whereas the ExpandoObject is really backed by an object[] internally.
On a side-note, Microsoft's System.Web.Helpers.Json behaves the same way. This test passes:
[TestMethod]
public void ExpandoObjectSerializesToJsonArray()
{
dynamic anonType = new { Value = 10, Product = "Apples" };
dynamic expando = new ExpandoObject();
expando.Value = 10;
expando.Product = "Apples";
var anonResult = System.Web.Helpers.Json.Encode(anonType);
var expandoResult = System.Web.Helpers.Json.Encode(expando);
Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", anonResult);
Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult);
}
One final edit:
You can make this work the way you want by turning your ExpandoObject into a Dictionary<string, object>. The caveat to this code is that it duplicates the data into a dictionary, so you have 2 copies in memory (or slightly less than, since technically the strings might be interned).
[TestMethod]
public void TestMethod1()
{
dynamic expando = new ExpandoObject();
expando.Value = 10;
expando.Product = "Apples";
// copy expando properties to dictionary
var dictionary = ((ExpandoObject)expando).ToDictionary(x => x.Key, x => x.Value);
var expandoResult = System.Web.Helpers.Json.Encode(expando);
var dictionaryResult = System.Web.Helpers.Json.Encode(dictionary);
Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult);
Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult);
}
Although, for anyone that comes across this later, and is actually using System.Web.Helpers.Json, the better thing to do is just wrap your ExpandoObject in a DynamicJsonObject like this:
[TestMethod]
public void TestMethod1()
{
dynamic expando = new ExpandoObject();
expando.Value = 10;
expando.Product = "Apples";
var dictionaryResult = System.Web.Helpers.Json.Encode(new DynamicJsonObject(expando));
Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult);
}
Ans once I worked through that, I found a similar question here: How to flatten an ExpandoObject returned via JsonResult in asp.net mvc?
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