0

I have a JSON file. Let's suppose it looks like this:

{
  "A": {
    "B": {
      "C": "12"
    }
  }
}

And a class Exp (this is a smaller version of a big class):

class Exp
{
    public string A = "A1";
    public string B = "B1";
    public string C = "C1";
    public string D = "D1";
} 

I want to change the JSON file to this:

{
  "A1": {
    "B1": {
      "C1": "12"
    }
  }
}

How can I achieve this?

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
Harsh Raj
  • 89
  • 1
  • 11
  • What did you use to de-serialize your first JSON into that object? Just re-serialize the object with the new values and you should get your desired output JSON. – rory.ap Oct 10 '19 at 12:56
  • Duplicate of : https://stackoverflow.com/questions/8796618/how-can-i-change-property-names-when-serializing-with-json-net – LeBigCat Oct 10 '19 at 13:03
  • I have to change the key not the value. Will that approach do the same? @rory.ap – Harsh Raj Oct 10 '19 at 13:04

3 Answers3

1

You can make a short helper method using Json.Net's LINQ-to-JSON API (JTokens) to accomplish this:

public static string RenameProperties(string json, Dictionary<string, string> nameMappings)
{
    JContainer token = (JContainer)JToken.Parse(json);

    // Note: We need to process the descendants in reverse order here
    // to ensure we replace child properties before their respective parents
    foreach (JProperty prop in token.Descendants().OfType<JProperty>().Reverse().ToList())
    {
        if (nameMappings.TryGetValue(prop.Name, out string newName))
        {
            prop.Replace(new JProperty(newName, prop.Value));
        }
    }

    return token.ToString();
}

To use it, pass your JSON string and a dictionary which maps the old names to the new names.

var nameMappings = new Dictionary<string, string>()
{
    { "A", "A1" },
    { "B", "B1" },
    { "C", "C1" },
};

string modifiedJson = RenameProperties(originalJson, nameMappings);

Working demo here: https://dotnetfiddle.net/rsq5ni

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
0

the correct solution I think it is, deserialize the JSON in a C # object, change the values ​​and re-serialize with the modified data.


    DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(Exp));  
       ExpbsObj2 = (Exp)deserializer.ReadObject(ms); 
    ExpbsObj2.A = "A1";
    ExpbsObj2.B = "B1";
    ExpbsObj2.C = "C1";
    ExpbsObj2.D = "D1";
    string output = JsonConvert.SerializeObject(ExpbsObj2);

but if you are sure of your Json you can try to make a Replace directly on the Json chain:


    string output = JsonString.Replace("\"A\"", "\"A1\"").Replace("\"B\"", "\"B1\"").Replace("\"C\"", "\"C1\"").Replace("\"D\"", "\"D1\"");;

Ahmed Msaouri
  • 316
  • 1
  • 10
  • thank you @Ahmed Msaouri, but that class Exp is just a small version of big class. If your approach can be more generic then it will be good – Harsh Raj Oct 10 '19 at 14:49
  • Yes, principally this solution worked for you, only if it is a class with many properties and you have a lot of data can it have performance problems and it takes the answer, in this case you will have to execute it in parallel (multithreading) – Ahmed Msaouri Oct 10 '19 at 15:03
0

Use two different classes:

[DataContract]
class Class1
{
    [DataMember]
    public string A { get; set; }

    public Class1()
    {

    }

    public Class2 GetClass2Clone()
    {
        return new Class2(this.A);
    }
}

[DataContract]
class Class2
{
    [DataMember(Name="A1")]
    public string A { get; set; }

    public Class2(string a)
    {
        this.A = a;
    }
}

Then use them like so:

Class1 class1 = JsonConvert.DeserializeObject<Class1>(json);
Class2 class2 = class1.GetClass2Clone();
string new_json = JsonConvert.SerializeObject(class2);

Instead of having Class1.GetClass2Clone() you could also use AutoMapper:

Mapper.Initialize(cfg =>
{
    cfg.CreateMap<Class1, Class2>();
});

Class1 class1 = JsonConvert.DeserializeObject<Class1>(json);
Class2 class2 = Mapper.Map<Class1, Class2>(class1);
string new_json = JsonConvert.SerializeObject(class2);
Arthur Rey
  • 2,990
  • 3
  • 19
  • 42