Changing Key Of An Property in Json - c#

I'm trying to make a json editor(works with treeview) these days, i did changing value function, i can change some keys as well, but i cant set keys in objects.
I can set the value:
SetValue(ref JObject main,JToken token,JToken newValue) {
//2nd argument is obj.SelectToken(node.Path)
token.Replace(newValue);
}
I can also set some keys:
SetKey(ref JObject main,JToken token,string newKey) {
//2nd argument is obj.SelectToken(node.Path)
//However, if token is in object, it seys the key of object because parent is object
(token.Parent as JProperty).Replace(newKey);
}
But how can i set the keys?
Regards.

You don't need to pass the original root object by ref and you don't need the original root at all. All you care about is the JToken and its parent.
In this case, you want to think of "replacement" as:
Add the old value by new key
Remove the old key/value pair
public void SetKey(JObject parent, JToken token, string newKey)
{
var tokenProp = token as JProperty;
var oldKeyName = tokenProp.Name;
parent[newKey] = tokenProp.Value;
parent.Remove(oldKeyName);
}
We can assume that if you are replacing a key for a key value pair, that the object is a JProperty token. In addition, if we are replacing keys, it is also safe to assume the parent is a JObject. You can call it as such:
var json = "{ 'key1': 'val1' }";
JObject parsedObj = JsonConvert.DeserializeObject<JObject>(json);
SetKey(parsedObj, parsedObj.First, "key2");

I had a similar issue where I had to remove whitespaces from all properties within a JObject, but didn't want to use a helper function. With using System.Linq:
var descendants = jObject.Descendants().Where(attr => attr is JProperty && ((JProperty)attr).Name.Contains(" ")).ToList();
descendants.ForEach(attr => attr.Parent[((JProperty)attr).Name.Replace(" ", string.Empty)] = ((JProperty)attr).Value);
descendants.ForEach(attr => attr.Remove());

Related

Adding a complex object to JObject using a delimited path/key

I am working with Jsons which I don't know their structure in advanced. Just for example:
{
"OrganizationData": {
"Org1": {
"Name": "Rega And Dodli",
"EmployessNum": "100000000"
},
"Org2": {
"Name": "Sami And Soso",
"EmployessNum": "2"
}
}
}
I'm currently getting values by using the SelectToken method to which I can pass a key with a sub key like this:
var token = myJObject.SelectToken("OrganizationData.Org1")
This works fine. Now I want to add a new entry to the JSON using a string like that, something like:
myJObject.Add("OrganizationData.Org3", myValueJson);
but calling add like that directly just adds a new key to the json called "OrganizationData.Org3" and not creating a new sub key called "Org3" inside "OrganizationData" like the current "Org1" and "Org2".
How can I add a new value with a delimited string like needed?
JSON doesn't have subkeys or delimited keys. OrganizationData.Org1 is a LINQ to JSON search expression, not a subkey.
To add Org3 you can use one of the many ways available to modify a JSON object. You can add a child element to OrganizationData or a sibling to one of the other Org nodes.
To add a child element to a node, you could use .SelectToken("OrganizationData") if you don't already have a reference to it, and use JObject.Add to add the new node. You'll have to cast the result to JObject first, as SelectToken returns a JToken. If there's a chance that OrganizationData is an array, you'll have to check the type too.
For example:
var token = myJObject.SelectToken("OrganizationData");
if(token is JObject orgObj)
{
orgObj.Add("Org3",myValueJson);
}
Working with unknown paths
The same thing works if the path is specified at runtime. In this case, all that's needed is to separate the last part from the rest of the path, perhaps using String.LastIndexOf`:
var lastDot=path.LastIndexOf('.');
if (lastDot<0)
{
//Oops! There's no dot. What do we do now?
}
var parent=path.Substring(0,lastDot);
var key=path.Substring(lastDot+1);
var token = myJObject.SelectToken(parent);
if(token is JObject orgObj)
{
orgObj.Add(key,myValueJson);
}
You'll have to decide what to do if the path contains no dot. Is this an invalid path? Or should a new object be added under the root object?

Replace Json properties with NewtonSoft

No idea where to begin with this, so I don't have any sample code.
I need to change the name of a property in a json document.
var json = (#"{""id"":""12"",
""title"":""My Title"",
""Chunks"":[
{
""id"":""137"",
""title"":""Title"",
""description"":""null"",
""selections"":[
{
""id"":""169"",
""title"":""Choice"",
""sort_order"":""null"",
""questions"":[
]
}
]
}
]
}
}
}");
I need to change the "id" that's got the value of 12 to "document_id" and leave the other ids alone. Are there any C# libraries like NewtonSoft that allow you to change the property rather than the property value. Seems like a common scenario but I haven't seen anything close to what I'm trying to do. I suppose I could convert the json to a string and do a replace, but that doesn't seem very elegant.
An approach using Newtonsoft.Json.Linq.JObject would look something like:
var obj = JObject.Parse(json);
obj["document_id"] = obj["id"]; // create new property called "document_id"
obj.Remove("id"); // remove the "id" property
Console.WriteLine(obj);
Also note that your JSON is not valid. It has two extra } at the end.
Assuming you would want to replace all the keys when there could be more than one node with key as "id" and value "12", you could use Linq to identify Tokens with Key "Id" and Value "12" and then use Add/Remove methods for creating a new node with different name.
For example,
JToken node = JToken.Parse(json);
var jObjectsWithTitle = node
.SelectTokens("$..*")
.OfType<JObject>()
.Where(x => x.Property("id") != null && Convert.ToInt32(x.Property("id").Value) == 12);
foreach(var item in jObjectsWithTitle)
{
item.TryGetValue("id",out var currentValue);
item.Add("document_id",currentValue);
item.Remove("id");
}

Get the path of a key from nested JSON using Json.Net

I have a big nested JSON. I don't know the structure of the JSON.
I just have a set of keys which are present in the JSON but I don't know where exactly in the JSON.
How do I find out the path of a key from an unknown JSON structure assuming the key exists somewhere in it?
If your JSON structure is unknown, you can parse it into a JToken like this:
JToken token = JToken.Parse(json);
From there, you can use either SelectToken() or SelectTokens() with a recursive descent JsonPath expression to find the property (or properties) matching a key:
JToken match = token.SelectToken("$.." + keyToFind);
Once you have the matching token, you can get the path to it using its Path property:
string path = match?.Path;
Here is a working demo which assumes you have multiple keys to find and each key can appear multiple times in the JSON: https://dotnetfiddle.net/9Em9Iq
For an unknown structure you can iterate over the objects :
var reader = new JsonTextReader(new StringReader(jsonText))
while (reader.Read())
{
// Do a condition on the variables reader.TokenType, reader.ValueType, reader.Value
}
This method will log all paths in your top level json that have a key equal to "key"
var keys = jobject.Properties().Where(p => p.Name == key).ToList();
keys.ForEach(i => Console.WriteLine(i.Path));
This will NOT work in a recursive way but it is easy from this to do a recursive search from there
you can use
JObject o = JObject.Parse(<yourjson>);
dynamic obj = o.SelectTokens("$..Product");

Serialize data to json string with dynamic property names

I have a method which accepts a key and a value. Both variables can have a dynamic content.
key => is a dynamic string which can be everything like e.g. "LastSentDate"
value => is an object which can be everything like e.g. "2014-10-10"
As key is a dynamic value like "LastSentDate" or whatever key is passed to the method then I want that the json property is the value of the key string and not literally key itself...
public void SetRowVariable(string key, object value)
{
var obj = new { key = value }; // key property is literally taken maybe anonym object is not a good idea?
string jsonString = JsonConvert.SerializeObject(obj);
// jsonString should have that output => "{ "LastSentDate": "2014-10-10" }"
}
How do I have to serialize the obj that I get the wished output?
It must also be possible that the "key" property can contain special chars like "!"ยง$%&/()=?"`
I am using .NET 3.5 sadly.
You could use a JObject (in Newtonsoft.Json.Linq):
var obj = new JObject();
obj[key] = JToken.FromObject(value);
string jsonString = obj.ToString();
You may try using a Dictionary<string, object>:
public void SetRowVariable(string key, object value)
{
var obj = new Dictionary<string, object>();
obj[key] = value; // Of course you can put whatever crap you want here as long as your keys are unique
string jsonString = JsonConvert.SerializeObject(obj);
...
}

dynamic JContainer (JSON.NET) & Iterate over properties at runtime

I'm receiving a JSON string in a MVC4/.NET4 WebApi controller action. The action's parameter is dynamic because I don't know anything on the receiving end about the JSON object I'm receiving.
public dynamic Post(dynamic myobject)
The JSON is automatically parsed and the resulting dynamic object is a Newtonsoft.Json.Linq.JContainer. I can, as expected, evaluate properties at runtime, so if the JSON contained something like myobject.myproperty then I can now take the dynamic object received and call myobject.myproperty within the C# code. So far so good.
Now I want to iterate over all properties that were supplied as part of the JSON, including nested properties. However, if I do myobject.GetType().GetProperties() it only returns properties of Newtonsoft.Json.Linq.JContainer instead of the properties I'm looking for (that were part of the JSON).
Any idea how to do this?
I think this can be a starting point
dynamic dynObj = JsonConvert.DeserializeObject("{a:1,b:2}");
//JContainer is the base class
var jObj = (JObject)dynObj;
foreach (JToken token in jObj.Children())
{
if (token is JProperty)
{
var prop = token as JProperty;
Console.WriteLine("{0}={1}", prop.Name, prop.Value);
}
}
EDIT
this also may help you
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(jObj.ToString());

Categories

Resources