.NET 6: Modify JSON in Memory with the System.Text.Json.Nodes Namespace

This blog post contains some notes to help me remember how to use the System.Text.Json.Nodes namespace in .NET 6 and beyond to modify JSON in memory.

The C# code that I previously migrated from Newtonsoft.Json to System.Text.Json serialized and deserialized between objects and JSON, but never explicitly updated the JSON. Recently, I had a need to update JSON before deserialization and realized that, until .NET 6, System.Text.Json is read-only, and therefore useful only for serialization and deserialization, not for modifying the JSON node tree in memory.

.NET six introduces the System.Text.Json.Nodes namespace for mutable JSON documents. Visual Studio community edition does not support the .NET 6 SDK, so I downloaded a prerelease version of JetBrains Rider that does.

The System.Text.Json.Nodes namespace contains classes for in-memory writable structured JSON manipulation. I think of JsonNode as read-only, use JsonObject to update, and I haven’t found a need for JsonArray or JsonValue.

I don’t know if you can convert a JsonElement (read-only in the System.Text.Json namespace) to a JsonNode, but you can parse its raw JSON.

JsonNode jsonNode = JsonNode.Parse(jsonElement.GetRawText());

For demonstration purposes, assume that I have a key named container and I want to move its child keys to the root. So, this:

{
  "container": {
    "move": "this is or was in the container",
    "this": {
      "also": "need to be moved"
    },
    "too": "."
  }
}

Would become:

{
  "move": "this is or was in the container",
  "this": {
    "also": "need to be moved"
  },
  "too": "."
}

This test code seems to work correctly.

using System.Text.Json.Nodes;

// source JSON to process
string jsonString = File.ReadAllText("test.json");
Console.WriteLine(jsonString);

// root node (opening curly brace)
JsonObject? root = JsonNode.Parse(jsonString)?.AsObject();

// if the root contains no key named "container" 
JsonNode? containerNode = root?["container"];

if (containerNode == null)
{
    return;
}

// get the names of the keys under the container key
List<string> keys = containerNode.AsObject().Select(
    child => child.Key).ToList();

// convert read-only JsonNode to writable JsonObject 
JsonObject container = containerNode.AsObject();

// iterate and move keys from container to root
foreach (string key in keys)
{
    JsonNode? move = containerNode[key];
    container.Remove(key);
    root?.Add(key, move);
}

root?.Remove("container");

Console.WriteLine(root);

Note that at least with Rider using .NET 6 with C# 10, the code for a command line tool apparently does not need a static class declaration and main() method (entry point), so this is actually the complete program (minus the test.json file). And I could still access something named args that I couldn’t see declared, and I think use types defined in the System namespace.

One thought on “.NET 6: Modify JSON in Memory with the System.Text.Json.Nodes Namespace

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: