Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to update JToken value

I'm trying to update the value of JToken but its reference is not getting updated.

JSON string:

    {
  "Title": "master",
  "Presentation": [
    {      
      "Component": {
        "Content": {
          "Title": "Set New Title",
        }
      }
    }
  ]
}

and the usage is given below

JObject jo = JObject.Parse(File.ReadAllText(file.json));
foreach (var token in jo.SelectTokens("$..Component.Content").Children())
            {
                JProperty prop = token.ToObject<JProperty>();
                prop.Value = "New Title";
            }
string jsonText = JsonConvert.SerializeObject(jo, Formatting.Indented);

In this example, I'm trying to update the value of Title property. It is getting updated within foreach, means local variable is getting updated but changes are not reflecting in main jobject.

Can anyone help me if i'm doing anything wrong?

like image 459
Balaji Avatar asked Jan 12 '17 00:01

Balaji


2 Answers

Once you call ToObject then you are working with a copy. If instead you try this, it should work:

JObject jo = JObject.Parse(File.ReadAllText(file.json));
foreach (var prop in jo.SelectTokens("$..Component.Content")
    .Children().OfType<JProperty>())
{
    prop.Value = "New Title";
}
string jsonText = JsonConvert.SerializeObject(jo, Formatting.Indented);

or to handle multiple types of JTokens:

JObject jo = JObject.Parse(File.ReadAllText(file.json));
foreach (var token in jo.SelectTokens("$..Component.Content")
    .Children())
{
    var prop = token as JProperty;
    if (prop != null) prop.Value = "New Title";
    var array = token as JArray;
    if (array != null)
    {
        // some other logic
    }
}

string jsonText = JsonConvert.SerializeObject(jo, Formatting.Indented);
like image 79
Stuart Avatar answered Oct 20 '22 07:10

Stuart


The answer from Stuart may be erroneous because "Content" may contain other children and all of theme could be renamed or their values could be changed.

I've encountered the similar issue. From the body I needed to remove value, because it was too long for logging and unnecesary, so I needed to change it's value. I could've changed it with indexer like token["name"], but "name" could be of different cases, so I needed an universal case independent way to erase it's value:

And I implemented it other way:

var jObject = JObject.Parse(body);

JToken token;
if (jObject.TryGetValue(
    Constants.FieldName,
    StringComparison.InvariantCultureIgnoreCase,
    out token))
{
    var jProperty = token.Parent as JProperty;
    if (jProperty != null)
    {
        jProperty.Value = "removed";
    }

    body = jObject.ToString(Formatting.Indented);
}
like image 27
Dmitry Dyachkov Avatar answered Oct 20 '22 06:10

Dmitry Dyachkov