I want to add a json property (name and value) or json data(array) to existing json string.
User has to specify a json path to specify where to add it.
Can someone help me to provide a link/example to progress on this.
Regards, Amar
If you want to set a existed place of path, you can use SelectToken:
void SetValueByPath(JToken token, string path, object value)
{
var newToken = value == null ? null : JToken.FromObject(value);
var targetToken = token.SelectToken(path);
if(targetToken.Type == JTokenType.Property)
targetToken.Replace(newToken)
}
But if you want to set a not existed place of path, here is the code:
//Origin code by Squirrel.Downy(Flithor)
public static void AddTokenByPath(JToken jToken, string path, object value)
{
// "a.b.d[1]['my1.2.4'][4].af['micor.a.ee.f'].ra[6]"
var pathParts = Regex.Split(path, @"(?=\[)|(?=\[\.)|(?<=])(?>\.)")
// > { "a.b.d", "[1]", "['my1.2.4']", "[4]", "af", "['micor.a.ee.f']", "ra", "[6]" }
.SelectMany(str => str.StartsWith("[") ? new[] { str } : str.Split('.'))
// > { "a", "b", "d", "[1]", "['my1.2.4']", "[4]", "af", "['micor.a.ee.f']", "ra", "[6]" }
.ToArray();
JToken node = jToken;
for (int i = 0; i < pathParts.Length; i++)
{
var pathPart = pathParts[i];
var partNode = node.SelectToken(pathPart);
//node is null or token with null value
if (partNode == null || partNode.Type == JTokenType.Null)
{
if (i < pathParts.Length - 1)
{
//the next level is array or object
//accept [0], not ['prop']
JToken nextToken = Regex.IsMatch(pathParts[i + 1], @"\[\d+\]") ?
new JArray() : new JObject();
SetToken(node, pathPart, nextToken);
}
else if (i == pathParts.Length - 1)
{
//JToken.FromObject(null) will throw a exception
var jValue = value == null ?
null : JToken.FromObject(value);
SetToken(node, pathPart, jValue);
}
partNode = node.SelectToken(pathPart);
}
node = partNode;
}
//set new token
void SetToken(JToken node, string pathPart, JToken jToken)
{
if (node.Type == JTokenType.Object)
{
//get real prop name (convert "['prop']" to "prop")
var name = pathPart.Trim('[', ']', '\'');
((JObject)node).Add(name, jToken);
}
else if (node.Type == JTokenType.Array)
{
//get real index (convert "[0]" to 0)
var index = int.Parse(pathPart.Trim('[', ']'));
var jArray = (JArray)node;
//if index is bigger than array length, fill the array
while (index >= jArray.Count)
jArray.Add(null);
//set token
jArray[index] = jToken;
}
}
}
a.b.d should be parsed to ['a']['b']['d'] not ['a.b.d']EDIT: After google'ing a bit I noticed .SelectToken()! This is exacly what I was thinking about when mentioning XPath.
// Inpup JSON
string input = "{ body: { name: { firstname: 'John', lastname: 'Doe' }, age: 43 } }";
JToken json = JToken.Parse(input); // Parsed to JToken as type may not be known.
// Select token based on JSONPath, see: http://goessner.net/articles/JsonPath/
JToken nameToken = json.SelectToken("$['body']['name']");
nameToken["middlename"] = "something";
// Prints: {"body":{"name":{"firstname":"John","lastname":"Doe","middlename":"something"},"age":43}}
string output = json.ToString(Newtonsoft.Json.Formatting.None);
OLD:
It seems like you want something like XPath for Json. So you can find an existing object/array and add to that?
My advice would be to search for an existing path tool for Json. Here's a quick and dirty example of how you may do it:
static void Main(string[] args)
{
string input = "{ body: { name: { firstname: 'John', lastname: 'Doe' }, age: 43 } }";
JToken json = JToken.Parse(input);
UpdateJson(json, "body/name/middlename", "Something");
// {"body":{"name":{"firstname":"John","lastname":"Doe","middlename":"Something"},"age":43}}
string output = json.ToString(Newtonsoft.Json.Formatting.None);
UpdateJson(json, "body/jobs", new JArray(){ "C# Dev", "Network Master" });
// {"body":{"name":{"firstname":"John","lastname":"Doe","middlename":"Something"},"age":43,"jobs":["C# Dev","Network Master"]}}
string output2 = json.ToString(Newtonsoft.Json.Formatting.None);
}
private static void UpdateJson(JToken source, string path, JToken value)
{
UpdateJsonInternal(source, path.Split('/'), 0, value);
}
private static void UpdateJsonInternal(JToken source, string[] path, int pathIndex, JToken value)
{
if (pathIndex == path.Length - 1)
{
if (source is JArray)
{
((JArray)source)[int.Parse(path[pathIndex])] = value;
}
else if (source is JObject)
{
((JObject)source)[path[pathIndex]] = value;
}
}
else if (source is JArray)
{
UpdateJsonInternal(((JArray)source)[int.Parse(path[pathIndex])], path, pathIndex + 1, value);
}
else if (source is JObject)
{
UpdateJsonInternal(((JObject)source)[path[pathIndex]], path, pathIndex + 1, value);
}
}
}
This adds or update the source with the JToken value at the path specified. So 'body/name/middlename' either adds 'middlename' to 'name' or updates it with 'value'. If 'name' does not exist, this example simply fails.
.SelectToken(). This function allows you to select a json token based on a path. The path you can read more about on: goessner.net/articles/JsonPath I've edited my answer with a simple exampleYou can just use Newtonsoft.Json:
var input = "{ test: true }";
var jObject = JObject.Parse(input);
jObject["updated"] = true;
jObject["array"] = new JArray("item1", "item2", "item3");
var s = jObject.ToString();
// { test: true, updated: true, array: ["item1", "item2", "item3"] }
Console.WriteLine(s);
Above we've parsed the json string in to a JObject then with that JObject we can start to modify it by adding fields etc.. then to get back the string representation we just call ToString on the JObject.