JSON data:
{
"return": {
"output01": "Test request success!!",
"output02": "test request"
}
}
C# code:
JObject obj = JObject.Parse(jsonString);
JToken jToken = obj["return"];
foreach (JToken item in jToken)
{
string output1_param = item["output01"].ToString();
string output2_param = item["output02"].ToString();
}
Think of a repeat case.
System.InvalidOperationException: 'Cannot access child value on
Newtonsoft.Json.Linq.JProperty.'
What's wrong?
item is a JProperty, so it does not support indexer by object key (for example string one). You need either strip foreach:
JToken jToken = obj["return"];
string output1_param = jToken["output01"].ToString();
string output2_param = jToken["output02"].ToString();
Or work with Values of item, for example via First:
foreach (JToken item in jToken)
{
Console.WriteLine(item.First.ToString());
}
Also in this case casting to JProperty in foreach is also an option:
foreach (JProperty item in jToken)
{
Console.WriteLine($"{item.Name} - {item.Value}");
}
as you can see in This Link, indexer of JToken does not implemented and your code tries to using indexer of JToken.
When you call GetEnumerator of jToken, in this sample you will get just single element which is JProperty, so calling indexer of JProperty(by using string key) which implemented JToken will try using this indexer and throws exception.
what happens if you call using this way:
jToken["output01"].ToString();
in this pattern you are using indexer of JObject, which iterates over ChildrenTokens of JObject and give you values.
as Guru said you must read value using value field or use First element.
Related
I'd like to iterate through a C# dictionary storing nested JSON to retrieve and pass the dictionary key name to a string, in the form of "key1:key1-1:key1-1-1".
After that, a new dictionary is created to use the specially arranged string as its keys.
Finally, desiredDictionary["key:key:key"] = originalDictionary["key"]["key"]["key"].
Please make the answer specific, my apology that I'm new to C# IEnumerable class and JSON.
I've stored the JSON data into a dictionary, the sample JSON is given below.
using System.Web.Script.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
......
string jsonText = File.ReadAllText(myJsonPath);
var jss = new JavaScriptSerializer();
//this is the dictionary storing JSON
var dictJSON = jss.Deserialize<Dictionary<string, dynamic>>(jsonText);
//this is the dictionary with keys of specially arranged string
var desiredDict = new Dictionary<string, string>();
......
......
//Here is a sample JSON
{
"One": "Hey",
"Two": {
"Two": "HeyHey"
}
"Three": {
"Three": {
"Three": "HeyHeyHey"
}
}
}
I need help with the process for dictionary key name retrieval, string completion, and new dictionary value passing.
According to the given JSON, desiredDict["Three:Three:Three"] = dictJSON["Three"]["Three"]["Three"] = "HeyHeyHey",
The solution is expected to apply on any similar JSON.
You can use a recursive method to take a JObject and produce a flattened dictionary from it like so:
private static IDictionary<string, string> FlattenJObjectToDictionary(JObject obj)
{
// obtain a key/value enumerable and convert it to a dictionary
return NestedJObjectToFlatEnumerable(obj, null).ToDictionary(kv => kv.Key, kv => kv.Value);
}
private static IEnumerable<KeyValuePair<string, string>> NestedJObjectToFlatEnumerable(JObject data, string path = null)
{
// path will be null or a value like Three:Three: (where Three:Three is the parent chain)
// go through each property in the json object
foreach (var kv in data.Properties())
{
// if the value is another jobject, we'll recursively call this method
if (kv.Value is JObject)
{
var childDict = (JObject)kv.Value;
// build the child path based on the root path and the property name
string childPath = path != null ? string.Format("{0}{1}:", path, kv.Name) : string.Format("{0}:", kv.Name);
// get each result from our recursive call and return it to the caller
foreach (var resultVal in NestedJObjectToFlatEnumerable(childDict, childPath))
{
yield return resultVal;
}
}
else if (kv.Value is JArray)
{
throw new NotImplementedException("Encountered unexpected JArray");
}
else
{
// this kind of assumes that all values will be convertible to string, so you might need to add handling for other value types
yield return new KeyValuePair<string, string>(string.Format("{0}{1}", path, kv.Name), Convert.ToString(kv.Value));
}
}
}
Usage:
var json = "{\"One\":\"Hey\",\"Two\":{\"Two\":\"HeyHey\" },\"Three\":{\"Three\":{\"Three\":\"HeyHeyHey\"}}}";
var jObj = JsonConvert.DeserializeObject<JObject>(json);
var flattened = FlattenJObjectToDictionary(jObj);
It takes advantage of yield return to return the results of the recursive call as a single IEnumerable<KeyValuePair<string, string>> and then returns that as a flat dictionary.
Caveats:
Arrays in JSON will throw an exception (see else if (kv.Value is JArray))
The else part for handling the actual values assumes that all values are convertible to string using Convert.ToString(kv.Value). If this is not the case, you will have to code for extra scenarios.
Try it online
I am trying to serialize an object to JSON using newtonsoft.json. The only thing is that I cannot append the json type to the field name. Consider this example:
var item = new {
value = "value",
data = new []{"str", "str"},
b = true
};
I want to convert that to
{
"value.string" : "value",
"data.array" : ["str", "str"],
"b.bool" : true
}
or something similar. The idea is to append the json type (not the c# type) to the json field. The reason I don't want to append the C# type is because it could be complex (sometimes the type is anonymous, sometimes it is IEnumerable, etc.)
I have seen many solutions that can convert to C# type such as implementing a IContractResolver. Unfortunately that doesn't work for this case.
I also do not know the type that I will convert before hand.
The closest I could get to is
public JObject Convert(JObject data)
{
var queue = new Queue<JToken>();
foreach (var child in data.Children())
{
queue.Enqueue(child);
}
while (queue.Count > 0)
{
var token = queue.Dequeue();
if (token is JProperty p)
{
if (p.Value.Type != JTokenType.Object)
{
token.Replace(new JProperty(
$"{p.Name}.{p.Value.Type}",
p.Value
));
}
}
foreach (var child in token.Children())
{
queue.Enqueue(child);
}
}
return data;
}
But it does not work for nested objects like
var result = convertor.Convert(JObject.FromObject(new { nested = new { item = "str"}}));
For some reason, Replace does not work for the nested objects. Not sure if it is a bug or not.
Your main problem is that, when you add a child JToken to a parent, and the child already has a parent, the child is cloned and the clone is added to the parent -- in this case your new JProperty. Then when you replace the original property with the new property, the cloned value hierarchy replaces the original value hierarchy in the overall JToken tree. And finally, when you do
foreach (var child in token.Children())
{
queue.Enqueue(child);
}
You end up looping through the original children that have already been cloned and replaced. While this doesn't matter when the property value is a primitive, it causes the problem you are seeing if the value is an array or other container.
(A secondary, potential issue is that you don't handle the possibility of the root container being an array.)
The fix is to prevent the wholesale cloning of property values by removing the property value from the old property before adding it to the new property, then later looping through the new property's children:
public static class JsonExtensions
{
public static TJToken Convert<TJToken>(this TJToken data) where TJToken : JToken
{
var queue = new Queue<JToken>();
foreach (var child in data.Children())
{
queue.Enqueue(child);
}
while (queue.Count > 0)
{
var token = queue.Dequeue();
if (token is JProperty)
{
var p = (JProperty)token;
if (p.Value.Type != JTokenType.Object)
{
var value = p.Value;
// Remove the value from its parent before adding it to a new parent,
// to prevent cloning.
p.Value = null;
var replacement = new JProperty(
string.Format("{0}.{1}", p.Name, value.Type),
value
);
token.Replace(replacement);
token = replacement;
}
}
foreach (var child in token.Children())
{
queue.Enqueue(child);
}
}
return data;
}
}
Working .Net fiddle.
Why does Json.NET clone the value when adding it to the new JProperty? This happens because there is a bi-directional reference between parents and children in the JToken hierarchy:
JToken.Children() iterates through all child tokens of a given token;
JToken.Parent gets the parent of a given token.
Thus a JToken cannot have two parents -- i.e., it cannot exist in two locations in a JToken hierarchy simultaneously. So when you add the property value to a new JProperty, what should happen to the previous parent? Possibilities include:
The previous parent is unmodified and a clone of the child is added to the new parent.
The previous parent is modified by replacing the child with a clone of its child.
The previous parent is modified by replacing the child with a null JValue.
As it turns out, Json.NET takes option #1, resulting in your bug.
Can I read JSON from string and iterate if I don't know what kind of key it stores?
Generally, it will be key value pair?
I know that I can use:
dynamic dynamicJson = JsonConvert.DeserializeObject(json);
But I don't have an access to keys.
I'm not trying to deserialize into strongly-typed .net objects.
You can use JObject.Parse method and iterate through KeyValuePair of JObject:
var jObject = JObject.Parse(json);
foreach (KeyValuePair<string, JToken> kvp in jObject)
{
// Your code.
}
I have some JSON that looks like this
[
{
"MobileSiteContent": {
"Culture": "en_au",
"Key": [
"NameOfKey1"
]
}
},
{
"PageContent": {
"Culture": "en_au",
"Page": [
"about-us/"
]
}
}
]
I parse this as a JArray:
var array = JArray.Parse(json);
Then, I loop over the array:
foreach (var content in array)
{
}
content is a JToken
How can I retrieve the "name" or "key" of each item?
For example, "MobileSiteContent" or "PageContent"
JToken is the base class for JObject, JArray, JProperty, JValue, etc. You can use the Children<T>() method to get a filtered list of a JToken's children that are of a certain type, for example JObject. Each JObject has a collection of JProperty objects, which can be accessed via the Properties() method. For each JProperty, you can get its Name. (Of course you can also get the Value if desired, which is another JToken.)
Putting it all together we have:
JArray array = JArray.Parse(json);
foreach (JObject content in array.Children<JObject>())
{
foreach (JProperty prop in content.Properties())
{
Console.WriteLine(prop.Name);
}
}
Output:
MobileSiteContent
PageContent
JObject obj = JObject.Parse(json);
var attributes = obj["parent"]["child"]...["your desired element"];
foreach (JProperty attributeProperty in attributes)
{
var attribute = attributes[attributeProperty.Name];
var my_data = attribute["your desired element"];
}
The default iterator for the JObject is as a dictionary iterating over key/value pairs.
JObject obj = JObject.Parse(response);
foreach (var pair in obj) {
Console.WriteLine (pair.Key);
}
Using Linq we can write something like:
JArray array = JArray.Parse(json);
foreach (JObject content in array.Children<JObject>())
{
List<string> keys = content.Properties().Select(p => p.Name).ToList();
}
If the JToken key name is unknown, and you only need the key's Value regardless of name, simply use the JToken.Values() method.
The below sample assumes the JToken value is a primitive type - first value found is extracted.
Solution can be extended to support Array values.
JToken fooToken = sourceData.
int someNum = fooToken .Values<int?>().First() ?? 0;
int someString = fooToken .Values<string>().First();
The simplest way is to look at the path of each item in the JSON object.
For Each token As JToken In json
Dim key= token.Path.Split(".").Last
Next
This is a very simple question but can't seem to find a direct answer. I read in a single JSON object. I then want to parse it and be able to directly address a token or a value and then format it for writing a file output, which I will use in another application. I am using C# and the Newtonsoft library.
My code:
JsonTextReader reader = new JsonTextReader(re);
while (reader.Read())
{
if (reader.Value != null)
Console.WriteLine("Value: {0}", "This is the value <Tags>: " + reader.Value);
}
How can I address each line? for example, desc and then Gets a reference to the game world. This must be so commoplace.
Thanks,
johnh
Use the JArray and JObject objects instead, like this:
var json = System.IO.File.ReadAllText("YourJSONFilePath");
var objects = JArray.Parse(json);
foreach(JObject root in objects)
{
foreach(KeyValuePair<String, JToken> tag in root)
{
var tagName = tag.Key;
Console.WriteLine("Value: {0}", "This is the value <Tags>: " + tagName);
}
}
Given a JToken token:
if (token.Type == JTokenType.Object)
{
foreach (var pair in token as JObject)
{
string name = pair.Key;
JToken child = pair.Value;
//do something with the JSON properties
}
}
else if (token.Type == JTokenType.Array)
{
foreach (var child in token.Children())
{
//do something with the JSON array items
}
}
else
{
//do something with a JSON value
}
Have a look at the properties of the reader as it's reading the string. Especially at the TokenType and Value properties. If you really need to read it sequentially that's the way to go. TokenType will be, in order, StartObject, PropertyName, String etc. depending on the node being read. Basically each time you see a PropertyName, the next one will be the property value.
Take note that you'd probably be better off using other techniques but it all depends.
I see that this thread is a bit old... However, #Karl Anderson, your answer was helpful. I just added a little bit to it which was way better than the 3 or 4 nested foreach loops that I had going on... see code below. Thank you for the help!
JArray jsonResponse = JArray.Parse(content);
Debug.WriteLine("\n\njsonResponse: \n" + jsonResponse);
foreach (JObject root in jsonResponse)
{
foreach (KeyValuePair<String, JToken> tag in root)
{
var tagName = tag.Key;
var variable = tag.Value;
Debug.WriteLine("Key: " + tagName + " Value: " + variable);
}
}