skip to Main Content

I am trying to serialize a JSON string to convert property names to camelCase using the System.Text.Json library. However, I still get the outcome with PascalCase.

Here is my code:

var stringJson = "{ "Key": "TextA" }";

var outcome = SerializeWithCamelCase(stringJson);

private static JsonElement SerializeWithCamelCase(string jsonContent)
{
    var options = new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        PropertyNameCaseInsensitive = true
    };

    using var document = JsonDocument.Parse(jsonContent);
    var element = document.RootElement;

    var jsonString = JsonSerializer.Serialize(element, options);

    using var camelCaseDocument = JsonDocument.Parse(jsonString);
    return camelCaseDocument.RootElement.Clone();
}

I’ve tried many things, but I still get an outcome with PascalCase.

I expect the output to have property names in camelCase, but I still get PascalCase.

Expected Output:

{
    "key": "TextA"
}

Actual Output:

{
    "Key": "TextA"
}

The final type must be JsonElement

2

Answers


  1. Use the below approach:

    using System;
    using System.Collections.Generic;
    using System.Text.Json;
    
    class Program
    {
        static void Main()
        {
            var stringJson = "{ "Key": "TextA" }";
            var outcome = SerializeWithCamelCase(stringJson);
            Console.WriteLine(outcome);
        }
    
        private static string SerializeWithCamelCase(string jsonContent)
        {
            using var document = JsonDocument.Parse(jsonContent);
            var root = document.RootElement;
            var modifiedObject = ConvertPropertyNamesToCamelCase(root);
            var options = new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                WriteIndented = true
            };
    
            return JsonSerializer.Serialize(modifiedObject, options);
        }
    
        private static JsonElement ConvertPropertyNamesToCamelCase(JsonElement element)
        {
            switch (element.ValueKind)
            {
                case JsonValueKind.Object:
                    var objBuilder = new Dictionary<string, JsonElement>();
                    foreach (var property in element.EnumerateObject())
                    {
                        var camelCaseName = ToCamelCase(property.Name);
                        var camelCaseValue = ConvertPropertyNamesToCamelCase(property.Value);
                        objBuilder[camelCaseName] = camelCaseValue;
                    }
                    return JsonDocument.Parse(JsonSerializer.Serialize(objBuilder)).RootElement;
    
                case JsonValueKind.Array:
                    var arrayBuilder = new List<JsonElement>();
                    foreach (var item in element.EnumerateArray())
                    {
                        var camelCaseItem = ConvertPropertyNamesToCamelCase(item);
                        arrayBuilder.Add(camelCaseItem);
                    }
                    return JsonDocument.Parse(JsonSerializer.Serialize(arrayBuilder)).RootElement;
    
                default:
                    return element.Clone();
            }
        }
    
        private static string ToCamelCase(string name)
        {
            if (string.IsNullOrEmpty(name))
                return name;
    
            if (name.Length == 1)
                return name.ToLowerInvariant();
    
            return char.ToLowerInvariant(name[0]) + name.Substring(1);
        }
    }
    

    The above approach will give you the output below:

    {
      "key": "TextA"
    }
    

    Refer to the working .netfiddle here

    Login or Signup to reply.
  2. The question doesn’t really ask how to serialize using Camel-case but how to convert a document using Pascal-case to camel-Case.

    The question’s problem is that JsonDocument.Parse produces a JsonDocument that represents the actual contents, not attributes that need serializing. There’s no way to change how JsonDocument handles parsing or deserialization. JsonDocument is read-only so it’s not possible to modify it either.

    To convert from Pascal-case to camel case, there are two options:

    • Use a custom converter that does use the policy or
    • Deserialize to a mutable JsonNode and modify the keys explicitly

    Use a custom type converter

    One option, shown in this related question is to use a custom converter that actually uses the naming policy. Note that the converter treats each element type explicitly :

    public class JsonElementConverter : JsonConverter<JsonElement>
    {
        public override void Write(Utf8JsonWriter writer, JsonElement value, JsonSerializerOptions options)
        {
            switch (value.ValueKind)
            {
                case JsonValueKind.Object:
                    var policy = options.PropertyNamingPolicy;
                    writer.WriteStartObject();
                    foreach (var pair in value.EnumerateObject())
                    {
                        writer.WritePropertyName(policy?.ConvertName(pair.Name) ?? pair.Name);
                        Write(writer, pair.Value, options);
                    }
                    writer.WriteEndObject();
                    break;
                case JsonValueKind.Array:
                    writer.WriteStartArray();
                    foreach (var item in value.EnumerateArray())
                        Write(writer, item, options);
                    writer.WriteEndArray();
                    break;
                default:
                    value.WriteTo(writer);
                    break;
            }
        }
        
        public override JsonElement Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            using var doc = JsonDocument.ParseValue(ref reader);
            return doc.RootElement.Clone();
        }
    }
    

    With that, the naming policy works :

    using var doc = JsonDocument.Parse(jsonString);
    
    JsonNamingPolicy policy = JsonNamingPolicy.CamelCase;
    var options = new JsonSerializerOptions
    {
        Converters = { new JsonElementConverter() },
        PropertyNamingPolicy = policy,
        WriteIndented = true // Or false, if you prefer
    };
    
    var serialized = JsonSerializer.Serialize(doc.RootElement, options);
    

    Using JsonNode

    The other option, mentioned in the related question but not implemented, is to deserialize to JsonNode and modify the keys. Once again, every element type must be handled. This time though, recursion is necessary to handle all nested elements.

    Despite that, the Camelize function isn’t that complicated:

    public static JsonNode Camelize(JsonNode node,JsonNamingPolicy policy)
    {
        if(node is JsonObject obj)
        {
            var pairs=obj.ToList();     
            foreach(var pair in pairs)
            {
                obj.Remove(pair.Key);
                obj[policy.ConvertName(pair.Key)]=Camelize(pair.Value,policy);
            }           
            return obj;         
        }
        if(node is JsonArray arr)
        {
            foreach(var item in arr)
            {
                Camelize(item,policy);
            }
            
            return arr;
        }
        return node;
    }
    

    This can camelize a complex object:

        var json="""
        {"Key":"TextA",
         "Key2":{"Apples":14},
         "Items":[{"Bazinga":"X"},
                  {"Bananas":{
                      "Potatoes":3,
                      "Moo":[1,2,3]}
                  }
                 ]}
        """;        
        var obj=JsonSerializer.Deserialize<JsonNode>(json);         
        
        var x=Camelize(obj,JsonNamingPolicy.CamelCase);
    
        var options=new JsonSerializerOptions{
            WriteIndented=true
        } ;
        
        Console.WriteLine( JsonSerializer.Serialize(x,options));
    

    The result is

    {
      "key": "TextA",
      "key2": {
        "apples": 14
      },
      "items": [
        {
          "bazinga": "X"
        },
        {
          "bananas": {
            "potatoes": 3,
            "moo": [
              1,
              2,
              3
            ]
          }
        }
      ]
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search