0

So I got this guy

{
  "lng_x": "106.883368",
  "style": "{\"name\":\"TACTICAL\"}"
}

Which I wanted to make into this guy

public class Root
{
    public string lng_x { get; set; }
    public Style style { get; set; }
}

public class Style
{
    public string name { get; set; }
}

But I got this instead

public class Root
{
    public string lng_x { get; set; }
    public string style { get; set; }
}

I know that the Json is supposed to be like this

{
  "lng_x": "106.883368",
  "style": 
  {
    "name": "TACTICAL"
  }
}

But I can't because it is already like that when I got it.

Is there any way so that I don't have to deserialize it again?

Izzan
  • 43
  • 4
  • 2
    If you can't fix the document, you'll have to deserialize again. You can create a custom type converter for the `style` property – Panagiotis Kanavos Aug 31 '22 at 07:42
  • What parser are you using? JSON.NET? System.Text.Json? – Panagiotis Kanavos Aug 31 '22 at 07:44
  • @PanagiotisKanavos I'm using Newtonsoft.Json / Json.NET. For now I am using a function to deserialize it again. I'm intrigued in what you say about converting it in the property, how do you do it? – Izzan Aug 31 '22 at 07:49
  • I suggest this has to be fixed at source. who ever doing this, probably they are doing double serialization – Krishna Varma Aug 31 '22 at 08:17
  • @KrishnaVarma Yes, I don't know whoever it is that made it, it needs to be fixed. The problem is they are already gone and my higher ups just said to ignore it and just try to deserialize it by myself :). – Izzan Aug 31 '22 at 08:22
  • Does this answer your question? [How to escape embedded JSON after unescape](https://stackoverflow.com/questions/51845381/how-to-escape-embedded-json-after-unescape) Also https://stackoverflow.com/questions/39154043/how-do-i-convert-an-escaped-json-string-within-a-json-object – Charlieface Aug 31 '22 at 10:20

3 Answers3

4

If you can't fix the JSON document you can create a custom JSON type converter and apply it to the style property. And whoever created that document needs to fix their bug.

If you use System.Text.Json, a possible converter could be :

public class StyleStringJsonConverter : JsonConverter<Style>
{
    public override Style Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options) =>
            JsonSerializer.Deserialize<Style>(reader.GetString()!);

    public override void Write(
        Utf8JsonWriter writer,
        Style style,
        JsonSerializerOptions options) =>
            writer.WriteStringValue(JsonSerializer.Serialize(style));
}

This can be applied through an attribute :

public class Root
{
    public string lng_x { get; set; }
    [JsonConverter(typeof(StyleStringJsonConverter))]
    public Style style { get; set; }
}

JSON.NET also has custom converters:

public class StyleStringConverter : JsonConverter<Style>
{
    public override void WriteJson(JsonWriter writer, Style value, JsonSerializer serializer)
    {
        writer.WriteValue(JsonConvert.SerializeObject(value));
    }

    public override Style ReadJson(JsonReader reader, Type objectType, Style existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        string s = (string)reader.Value;

        return JsonConvert.DeserializeObject<Style>(s);
    }

}

This can be applied using an attribute too:

public class Root
{
    public string lng_x { get; set; }
    [JsonConverter(typeof(StyleStringJsonConverter))]
    public Style style { get; set; }
}
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • Ok let me try it. And yes, whoever created the code in the first place needs to fix it. But it was already implemented in the system and there's ton of datas that already saved like that, and my higher ups just said to ignore it and just deserialize it by myself :' – Izzan Aug 31 '22 at 07:58
  • It works! But I noticed that when I try to serialize it again it returns again into '"style": "{\"name\":\"TACTICAL\"}"'. Will it always be like that if the code is not fixed? Or can I change it into '"style": {"name": "TACTICAL"}' – Izzan Aug 31 '22 at 08:20
  • Try `writer.WriteValue(value);` in that case. If you want to generate JSON in both formats you can also pass the converter as an option to the serializer instead of using an attribute – Panagiotis Kanavos Aug 31 '22 at 08:23
  • It returns with an error JsonWriterException: Unsupported type: HelperPlotting.Style. – Izzan Aug 31 '22 at 08:26
  • In that case try `writer.WriteRaw(JsonConvert.SerializeObject(value))`. This writes the string as-is – Panagiotis Kanavos Aug 31 '22 at 08:38
  • Just tried it, it does not work. But if you change it to WriteRawValue it does work. – Izzan Aug 31 '22 at 08:45
  • Sounds like you could create a completely generic form of this converter. I feel like there should be a dupe somewhere – Charlieface Aug 31 '22 at 10:18
  • @Charlieface yes, I've thought this from the start, but that's not what the question is about. Using `T` instead of `Style could cause confusion when people don't know about converters. Besides, the OP wants to generate valid JSON instead of a JSON string on serialization – Panagiotis Kanavos Aug 31 '22 at 10:21
0

As stated before, the original creators should fix your the JSON file. Meanwhile, you are stuck with it.

To make sure you don't dirty your own code

  1. use Regex to make it a real JSON
  2. Deserialize as normal

Advantage: When the JSON is changed to a correct form you have to remove the CleanJSON Method and your code will stay working.

The Code

using System.Text.Json;
using System.Text.RegularExpressions;

function YourFunction(){
    //-- Get your JSON in string format (from API, file,...)
    string _jsonString = ... ;
    CleanJSON(_jsonString);
    YourModels.Root _correctStructure = (JsonSerializer.Deserialize<YourModels.Root>(_JSsonString);
}

function CleanJSON(string jsonString){
    //__ Probably you can group the regex
    string _regexPatternRoot = @"(\\"")(.*?)(\\)";
    string _regexReplacementRoot = @"""$2";
    string _regexPatternStyle = "\"({)\"(.*?)\"}\"";
    string _regexReplacementStyle = @"$1""$2""}";

    _JSsonString = Regex.Replace(_JSsonString, _regexPatternRoot, _regexReplacementRoot);
    _JSsonString = Regex.Replace(_JSsonString, _regexPatternStyle, _regexReplacementStyle);
}
0

you don't need any custom converter. The problem is that your origional style property is a json string and you have to deserialize it. In this case I usually use a JsonConstructor

public class Root
{
    public string lng_x { get; set; }
    public Style style { get; set; }
    
    [JsonConstructor]
    public Root (string style)
    {
        this.style=JsonConvert.DeserializeObject<Style>(style);
    }
    public Root (){}
}

test

Root data = JsonConvert.DeserializeObject<Root>(json);

{
  "lng_x": "106.883368",
  "style": {
    "name": "TACTICAL"
  }
}
Serge
  • 40,935
  • 4
  • 18
  • 45
  • This is actually much simpler than using the custom converter. But I think I still gonna accept the Custom Converter answer because it also gives details on how to make a custom converter either on Json.Net or string.json. Thank you though !! – Izzan Sep 01 '22 at 08:46