skip to Main Content

I’m working on a library to parse Minecraft JSON files. However, they have a slightly weird format that I can’t figure out how to parse with Newtonsoft’s JSON.net:

{
    "values": [
        "some_object",
        "another_object",
        {
            "name": "third_object",
            "required": false
        }
    ]
}

The class I’m trying to deserialize the values array into looks like this:

class TagValue
{
    public string Name;
    public bool Required = false;
}

So for values which are just a string, it should set Name to the string and leave Required as false.

Is there a way I can do this? I’m very new to the library and can’t figure out how to do anything more advanced than the most basic deserialization.

2

Answers


  1. Try this

    [JsonConverter(typeof(TagValueConverter))]
    class TagValue
    {
        [JsonProperty("name")]
        public string Name { get; set; }
    
        [JsonProperty("required")]
        public bool Required { get; set; }
    
        private class TagValueConverter : JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                return objectType == typeof(string) ||
                    objectType == typeof(TagValue);
            }
    
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                if (reader.TokenType == JsonToken.String)
                    return new TagValue
                    {
                        Name = reader.Value as string
                    };
                else
                {
                    var jobj = JObject.Load(reader);
                    var obj = new TagValue();
                    serializer.Populate(jobj.CreateReader(), obj);
                    return obj;
                }
            }
    
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                throw new NotImplementedException();
            }
        }
    }
    

    Then presumably you have/need a class for the outer object:

    class TagValues
    {
        [JsonProperty("values")]
        public TagValue[] Values { get; set; }
    
        public static void TestMe()
        {
            string json = @"{
                ""values"": [
                    ""some_object"",
                    ""another_object"",
                    {
                        ""name"": ""third_object"",
                        ""required"": true
                    }
                ]
            }";
    
            var tags = JsonConvert.DeserializeObject<TagValues>(json);
    
            Debug.Assert(tags.Values?.Length == 3);
            Debug.Assert(tags.Values[0].Name == "some_object");
            Debug.Assert(tags.Values[1].Name == "another_object");
            Debug.Assert(tags.Values[2].Name == "third_object" &&
                        tags.Values[2].Required == true);
        }
    }
    

    PS – You also should make those fields properties as was suggested in the comments.

    Login or Signup to reply.
  2. you don’t need any converters, just one string of code is plenty

        List<TagValue> values = JObject.Parse(json)["values"]
                    .Select(va => va.Type == JTokenType.Object
                    ? va.ToObject<TagValue>()
                    : new TagValue { Name = (string) va }
                    ).ToList();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search