I'm developing an application that reads some JSON data and makes some statistics, but now I've run into a problem.
I have a string like this:
{
"position":[
{
"someKey1":"someVal1",
"someKey2":"someVal2",
},
{
"someKey1":"someVal3",
"someKey2":"someVal4",
}
}
I want to access the someKeys and someValues.
I'm converting it to a dictionary like this:
Dictionary<string, object> values = deserializeJSON(json_string);
Edit 1: Sorry, forgot to add deserializeJSON:
private Dictionary<string, object> deserializeJSON(string p_jsonObject)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Deserialize<Dictionary<string, dynamic>>(p_jsonObject);
}
Now I have trouble getting access to the list of values with the key "position". If I try to print the type of values["position"] I get:
System.Collections.ArrayList
So I thought I could just iterate through this, but I can't. I tried using enumerator (read in here that it would make it possible to iterate over the objects, and that I have to add it to an ArrayList to cast it):
ArrayList arr = new ArrayList();
IEnumerable enumerable = values["position"] as IEnumerable;
foreach (object element in enumerable)
{
arr.Add(element);
}
When I print arr[0] I get:
System.Collections.Generic.Dictionary`2[System.String,System.Object]
Here I'm confused. I assume it's the list of someKeys and someVals, which should be correct, right?
Now I've tried, with no luck, getting access to these values. I tried arr[0]["someKey1"] but get an error that I cannot apply indexing to 'object'.
Any ideas on a solution? Ideally a more elegant solution? :)
Thanks in advance
You can use Linq to JSON (add Newtonsoft's JSON.NET from NuGet):
JObject jo = JObject.Parse(json);
var value = (string)jo["position"][1]["someKey1"]; // someVal3
Another sample:
JObject jo = JObject.Parse(json);
JArray positions = (JArray)jo["position"];
foreach (var item in positions)
{
// use (string)item["someKey1"]
// use (string)item["someKey2"]
}
You can access the elements as follows:
var enumerable = (IEnumerable)values["position"]; // Will get you the enumerable ArrayList
(Dictionary<string,object>)values["position"][0]; // Will get you the First element of the ArrayList
(string)values["position"][0]["someKey1"]; // Will get you someKey1 from the first position of position
Related
I am new to C# and JSON and need some help in getting the Key name(s) in a list of a nested JSON object. The keys are dynamic so I won't necessarily know the keys.
sample code I've tried.
```
protected void test()
{
var mystring = #"{
""zone1"": {
""sites"": {
""site1"": {
""to"": ""email1"",
""subject"": ""subjecttxt"",
""link"": ""somesite""
},
""site2"": {
""to"": ""email1"",
""subject"": ""subject"",
""link"": ""somesite""
}
},
""zone2"": {
""to"": ""email1"",
""subject"": ""subject"",
""link"": ""somelink""
}}";
var rss = JObject.Parse(mystring);
foreach (var section in rss)
{
Console.Write(section.Key);
IList<JToken> result = rss["zone1"]["sites"].Children().ToList();
var zone = section.Key;
var site = rss[zone]["sites"];
foreach (var subsite in rss["zone1"]["sites"])
{
var subs = subsite.Parent.ToString();
// some other code
}
}
}
```
Looking for a result:
site1,
site2,
...
I can get the children as IList but looking for something similar to "section.Key" as noted above.
Thank you for your help.
I believe what you are looking for is to get the properties of the sites. Since accessing the rss["zone1"]["sites"] returns a JToken, you will need to convert that to JObject and then use Properties() method to get the data you need.
var sites = ((JObject)rss["zone1"]["sites"]).Properties();
Then you can simply iterate over the IEnumerable<Jproperty> to get the Name of the property or whatever else you need from under it.
To get the section.Key for the sites, you can use the following code.
foreach(var site in (JObject)rss["zone1"]["sites"]) {
Console.WriteLine(site.Key);
}
Output:
site1
site2
Your first call to JObject.Parse already does all the work of converting a string into a structured JSON object. The currently-accepted answer redoes some of this work by (1) turning a structured JSON object back into a string, and then (2) re-parsing it with JObject.Parse. There is a simpler way.
Instead, you can cast the value stored at rss["zone1"]["sites"] into a JObject. (The expression rss["zone1"]["sites"] has type JToken, which is a parent class of JObject, but in this case we happen to know that rss["zone1"]["sites"] is always JSON object, i.e. a collection of key-value pairs. Therefore, this cast is safe to perform.)
This is what the code might look like:
var sites = (JObject) rss["zone1"]["sites"];
foreach (var site in sites)
{
Console.WriteLine(site.Key);
}
I am having trouble finding the JObject nested keys in order to convert the key values to an array. The code below seems to only get the parent keys instead of the entire object.
What I want: Convert any ValuesToList items in the JObject to JArray if they are not already an array irregardless of how nested the keys are. NOTE: Solution should work with entirely different Json models.
Purpose: Sometimes the Json returns as a model instead of an array which causes deserializing to a model to throw exceptions.
result = {{ "errors": null, "content": { "officeId": 1, "daysClosed": [] } }}
// values in ValuesToList are "content" and "daysClosed"
var result = JObject.Parse(_responseString);
foreach (string item in ValuesToList.ToArray())
{
// Check to see if toList value is contained in the JObject.
if (result[item] != null)
{
// Check to see if the value is an array. If not, will convert to array/list Json.
if (!(result[item] is JArray))
result[item] = new JArray(result[item]);
}
}
The problem is that I am unable to find daysClosed in the JObject because it is a child. Thus, when item = "daysClosed" the result[item] will return null.
I was working on a way to use reflection to solve this problem but ran into issues where a new JObject would be appended to the current JObject and I am looking to replace the Keys values with an array if the keyvalue exists and is not already an array.
Since your keys can occur at any depth in the JObject, you'll need to use SelectTokens along with a JsonPath expression to find them. Something like this should work:
foreach (string item in ValuesToList.ToArray())
{
// find all occurrences of the item in the JObject at any depth
foreach (JToken match in result.SelectTokens("$.." + item))
{
// if the matching token is not an array, wrap it in an array
if (match.Type != JTokenType.Array)
{
JProperty parent = (JProperty)match.Parent;
parent.Value = new JArray(match);
}
}
}
Fiddle: https://dotnetfiddle.net/EtDqNs
why don't you try doing this:
var arrayProperties = result.DoSomething().OfType<JProperty>().Where(prop => prop.Value.Type == JArray);
I have a list of JSON objects, each of which I'm iterating over and I simply want to process all of the KeyValuePairs therein so that the keys are uppercased, then return the revised objects.
This is what I attempted:
public static List<JObject> normalizeKeys(List<JObject> jObjList)
{
jObjList.ForEach(jobj => {
foreach(var kvp in jobj)
{
kvp.Key = kvp.Key.ToUpper();
}
});
return jObjList;
}
but it doesn't execute and instead I get KeyValuePair<string, JToken>.Key cannot be assigned to -- it is readonly. Does anyone have any suggestions for how to accomplish what I'm after?
Though the given answer works, I would be inclined to say that it is both not as elegant as it could be, and not as generally useful as it could be. We can make it more of both. To begin with, solve the problem for one object:
public static JObject NormalizeKeys(JObject originalObject)
{
var newObject = new JObject();
foreach (var kvp in originalObject)
newObject.Add(kvp.Key.ToUpper(), kvp.Value);
return newObject;
}
And now to solve the problem for a list:
var newList = oldList.Select(x=>NormalizeKeys(x)).ToList();
Or, even shorter:
var newList = oldList.Select(NormalizeKeys).ToList();
Isn't that much more pleasant than all that nested loop stuff? Say how to normalize one object, and then say that you want to apply that function to the list, and you're done.
Guess you know the answer yourself, you must create a new collection and copy the items over, since key is key, it's case sensitive, and cannot be changed, as otherwise you might end up with probably 2 sets of data, one set with normal case, and the other with upper cases.
The solution is as the following:
public static List<JObject> normalizeKeys(List<JObject> jObjList)
{
// create a new list for return and copy over the existing items
var jObjReturnList = new List<JObject>(jObjList.Count);
jObjList.ForEach(jobj =>
{
var jObjNew = new JObject();
foreach (var kvp in jobj)
{
jObjNew.Add(kvp.Key.ToUpper(), kvp.Value);
}
jObjReturnList.Add(jObjNew);
});
return jObjReturnList;
}
I have an IEnumerable<KeyValuePair<string,string>>, from which I would like, ideally, an anonymous object which has the keys as property names and the values as property values.
I've tried various selection expressions (none of which even compiled...) and an approach using ExpandoObject (see below), but without success. Is there a good way to do this? If possible, I'd like to avoid an extra explicit iteration over the collection (i.e. do it all with a LINQ statement of some sort).
This is what I've tried so far. I hope it also clarifies what I'm trying to do:
var kvps = getProps(); // returns IEnumerable<KeyValuePair<string,string>>
dynamic o = new ExpandoObject();
foreach (var kvp in kvps)
{
o.Add(kvp);
}
This is OK at compile time, but at runtime I get a YSOD stating 'System.Dynamic.ExpandoObject' does not contain a definition for 'Add' - I guess it works at compile time because o is dynamic, so the compiler can't know if a method .Add() has been added to it since it was instantiated. The odd thing is, that on the MSDN documenation page for ExpandoObject .Add() is listed as one of several "explicitly implemented interface methods".
It is not necessary for me to get this into a dynamic object - I just need to get something that has property names and values according to the keys and values of the key-value pairs.
Update: Well, this is embarrassing. Turns out this was something of an XY-problem too.
I'm trying to render this to JSON using the built-in features of ASP.NET MVC, by simply returning Json(data) in my controller. The answers all worked very well to do what I first asked, but when I pass this object as data I still don't get what I want:
// What I get:
[
{ Key: 'firstkey', Value: 'FirstValue' },
{ Key: 'secondKey', Value: 'secondValue' }
]
// What I want:
{ firstKey: 'FirstValue', secondKey: 'secondValue' }
Apparently, an ExpandoObject with the relevant properties added didn't cut it - it was cast to a dictionary before rendering...
You need to use the ExpandoObject as an IDictionary<string, object> while populating it:
var kvps = getProps(); // returns IEnumerable<KeyValuePair<string,string>>
IDictionary<string, object> o = new ExpandoObject();
foreach (var kvp in kvps)
{
// Or use Add(kvp.Key, kvp.Value), if you want
o[kvp.Key] = kvp.Value;
}
dynamic d = o;
// Now you can use the properties
ExpandoObject explicitly implements IDictionary<string, object> - so you need to cast it to one first:
var kvps = getProps();
dynamic o = new ExpandoObject();
var dict = o as IDictionary<string, object>;
foreach (var kvp in kvps)
{
dict.Add(kvp.Key, kvp.Value);
}
Now you can use o as you would expect:
var example = o.YourKey;
I'm trying to render this to JSON using the built-in features of ASP.NET MVC, by simply returning Json(data) in my controller.
Interesting.
To do that, you serialize a dictionary, not an ExpandoObject. MVC 3's JSON serializer already does that with a dictionary. All you have to do is convert your IEnumerable<KeyValuePair<string, object>> to a dictionary:
var kvps = getProps();
var dictionary = kvps.ToDictionary(k => k.Key, v => v.Value);
return Json(dictionary, JsonRequestBehavior.AllowGet); //take out allow get if you don't need it.
No dynamics required.
I think you have to cast your expando object to IDictionary and call Add(string, object)
I'm using C# and Json.NET. If I have a JObject, I want a list of the keys within the object, similar to how object.Keys() returns the keys within the object. This seems like it'd be obvious, but I'm having a rough time finding a way to do this.
Edit:
I'm traversing through the object, and I want to spit out all the keys in the object as I go through. I realize that this example will result in seeing the same key multiple times, and that's OK for my needs.
public void SomeMethod(JObject parent) {
foreach (JObject child in parent.Children()) {
if (child.HasValues) {
//
// Code to get the keys here
//
SomeMethod(child);
}
}
}
IList<string> keys = parent.Properties().Select(p => p.Name).ToList();
Documentation: JObject.Properties
From Converting a JSON.NET JObject's Properties/Tokens into Dictionary Keys
You can simply convert the JObject into a Dictionary object and access the method Keys() from the Dictionary object.
Like this:
using Newtonsoft.Json.Linq;
//jsonString is your JSON-formatted string
JObject jsonObj = JObject.Parse(jsonString);
Dictionary<string, string> dictObj = jsonObj.ToObject<Dictionary<string, string>>();
You can now access those keys via the dictObj.Keys() method. You can see if a key exists by performing dictObj.ContainsKey(keyName) also.
Obviously, you can format the Dictionary however you want (could be Dictionary<string, object>, etc.).