1

I am trying to parse into different items a JSON file that has items with the following example content:

{
    "PM00000001": { "description": "Manufacturing","cost": -1,"group":"Manufacturing","WeldAngleDegrees": 60},
    "PM00000010": {"description": "Plate Roll","cost": 90,"unit": "hr","group": "Roll","setup": 0.5,"speed": 0.4},
    "PM00000011": {"description": "Weld SAW","cost": 90,"unit": "hr","group": "Weld","width": 0.5,"thickness": 50}
}

Each item has a description, cost and group. The rest of the attributes depend on the group. In the example above Manufacturing has "WeldAngleDegrees", Roll has setup and speed, and Weld has width and thickness.

I am trying to use JSON.NET to parse this file.

Right now I am doing this:

string text = System.IO.File.ReadAllText(ofd.FileName);
Dictionary<string, Item> deserializedProduct = JsonConvert.DeserializeObject<Dictionary<string, Item>>(text, new ItemConverter());

with

public class Item
{
    public string description { get; set; }
    public double cost { get; set; }
    public string group { get; set; }
}

public class ManufacturingItem : Item
{
    public string WeldAngleDegrees { get; set; }
}

public class ItemConverter : CustomCreationConverter<Item>
{
    public override Item Create(Type objectType)
    {
        return new ManufacturingItem();
    }
}

Is there a way in ItemConverter to figure out which "group" the item belongs to to create the correct item type?

Is there an easier way to do this?

Sumner Evans
  • 8,951
  • 5
  • 30
  • 47
Andrew
  • 521
  • 7
  • 18

2 Answers2

2

Instead of deriving your ItemConverter from CustomCreationConverter<T>, derive it from JsonConverter; then you will have access to the JSON via the reader. You can load the object data into a JObject, then inspect the group property to determine which class to create. Here is how the code might look:

public class ItemConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Item);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        string group = (string)jo["group"];
        if (group == "Manufacturing")
        {
            return jo.ToObject<ManufacturingItem>();
        }
        else if (group == "Roll")
        {
            return jo.ToObject<RollItem>();
        }
        else if (group == "Weld")
        {
            return jo.ToObject<WeldItem>();
        }
        throw new JsonSerializationException("Unexpected item (group) type");
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Fiddle: https://dotnetfiddle.net/8ZIubu

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • This is what I needed. A question though. I am reading the JSON in from a text file and going through the ReadJson function it keeps setting jo to the first item in the file and results in an infinite loop. Any ideas? – Andrew Feb 16 '15 at 15:04
  • Try changing the above code so that when it calls `jo.ToObject()` it does not pass the serializer. That way a new serializer will be used which will not have the converter, and so you should not get into an infinite loop. I'll edit my answer. – Brian Rogers Feb 16 '15 at 15:11
1

Just deserialize your json to a dictionary, and interpret the values according to the value of group.

var dict = JsonConvert.DeserializeObject<Dictionary<string, MyItem>>(json);

public class MyItem
{
    public string Description { get; set; }
    public int Cost { get; set; }
    public string Group { get; set; }
    public int WeldAngleDegrees { get; set; }
    public string Unit { get; set; }
    public double Width { get; set; }
    public int Thickness { get; set; }   
    public double Speed { get; set; }
    public double Setup { get; set; } 

}
EZI
  • 15,209
  • 2
  • 27
  • 33
  • EZI. I started with this and it worked until I ran into two different groups that had implemented "Speed" differently. One as a double and the other as a list. – Andrew Feb 16 '15 at 15:05
  • @user2235373 see [this](http://stackoverflow.com/questions/22052430/how-to-handle-json-that-returns-both-a-string-and-a-string-array). Similar problem – EZI Feb 16 '15 at 16:22