LearningJrDev
LearningJrDev

Reputation: 941

Move property child object to root

I have a c# object that natively serializes to

{
  "LrsFeature": {
    "MEASURE": 1.233242,
    "STATION_ID": "brians station",
    "NLF_ID": "brians route"
  },
  "EVENT_ID": "00000000-0000-0000-0000-000000000000",
}

and I want it to be

{
  "MEASURE": 1.233242,
  "STATION_ID": "brians station",
  "NLF_ID": "brians route",
  "EVENT_ID": "00000000-0000-0000-0000-000000000000",
}

where all the properties within LrsFeature are added to the root level.

My attempt

            var events = JObject.FromObject(LrsEvent);
            var attrs = JObject.FromObject(LrsEvent.LrsFeature);

            events.Merge(attrs, new JsonMergeSettings
            {
                MergeArrayHandling = MergeArrayHandling.Union
            });

This gives me

{
  "MEASURE": 1.233242,
  "STATION_ID": "brians station",
  "NLF_ID": "brians route",
  "LrsFeature": {
    "MEASURE": 1.233242,
    "STATION_ID": "brians station",
    "NLF_ID": "brians route"
  },
  "EVENT_ID": "00000000-0000-0000-0000-000000000000",
}

I then need to delete the LrsFeature object, but it seems a little bit hacky. I figured JSON.NET might have a more direct method of doing this

Upvotes: 3

Views: 2030

Answers (3)

Johan Larsson
Johan Larsson

Reputation: 17590

An extension method handling a simple case:

public static JProperty MoveToParent(this JProperty property)
{
    if (property is { Parent: JObject { Parent: JProperty { Parent: JObject parent } } })
    {
        property.Remove();
        parent.Add(property);
        return property;
    }

    throw new InvalidOperationException("Could not move to parent.");
}

Upvotes: 0

Brian Rogers
Brian Rogers

Reputation: 129777

You can do what you want like this:

    JObject jo = JObject.FromObject(LrsEvent);
    JProperty lrs = jo.Property("LrsFeature");
    jo.Add(lrs.Value.Children<JProperty>());
    lrs.Remove();
    string json = jo.ToString();

Fiddle: https://dotnetfiddle.net/zsOQFE

Upvotes: 2

Kyle
Kyle

Reputation: 5557

What you're looking to do is deserialize a JSON string and then deep-flatten it. You can do this using the recursive method:

Code

public class JsonExtensions
{
    /// <summary>
    /// Deeply flattens a json object to a dictionary.
    /// </summary>
    /// <param name="jsonStr">The json string.</param>
    /// <returns>The flattened json in dictionary kvp.</returns>
    public static Dictionary<string, object> DeepFlatten(string jsonStr)
    {
        var dict = new Dictionary<string, object>();
        var token = JToken.Parse(jsonStr);
        FillDictionaryFromJToken(dict, token, String.Empty);
        return dict;
    }

    private static void FillDictionaryFromJToken(Dictionary<string, object> dict, JToken token, string prefix)
    {
        if(token.Type == JTokenType.Object)
        {
            foreach (var property in token.Children<JProperty>())
            {
                FillDictionaryFromJToken(dict, property.Value, property.Name);
                // Uncomment and replace if you'd like prefixed index
                // FillDictionaryFromJToken(dict, value, Prefix(prefix, property.Name));
            }
        }
        else if(token.Type == JTokenType.Array)
        {
            var idx = 0;
            foreach (var value in token.Children())
            {
                FillDictionaryFromJToken(dict, value, String.Empty);
                idx++;
                // Uncomment and replace if you'd like prefixed index
                // FillDictionaryFromJToken(dict, value, Prefix(prefix, idx.ToString()));
            }
        }
        else // The base case
        {
            dict[prefix] = ((JValue)token).Value; // WARNING: will ignore duplicate keys if you don't use prefixing!!!
        }
    }

    private static string Prefix(string prefix, string tokenName)
    {
        return String.IsNullOrEmpty(prefix) ? tokenName : $"{prefix}.{tokenName}";
    }

}

Usage

var jsonStr = "{\"LrsFeature\":{\"MEASURE\":1.233242,\"STATION_ID\":\"brians station\",\"NLF_ID\":\"brians route\"},\"EVENT_ID\":\"00000000-0000-0000-0000-000000000000\"}";
var dict = JsonExtensions.DeepFlatten(jsonStr);

foreach (var kvp in dict)
    Console.WriteLine($"{kvp.Key}={kvp.Value}");

Upvotes: 1

Related Questions