aherrick
aherrick

Reputation: 20169

Deserialize JSON string with child objects embedded in a string value

I have a JSON String that I'm trying to deserialize to C# in one swoop.

The Children nodes of SalesLines is a string representation. I want objects all the way down when I deserialize. What is the best way to this with JSON.NET?

{
   "value":[
      {
         "documentType":"Quote",
         "SONumber":"S-QUO1001",
         "SalesLines":"[{\"SONumber\":\"S-QUO1001\",\"LineNum\":10000,\"ItemId\":\"1936-S\",\"ItemAttributes\":[{\"AttibuteName\":\"COLOR\",\"AttributeValue\":\"YELLOW\"},{\"AttibuteName\":\"DEPTH\",\"AttributeValue\":\"100\"},{\"AttibuteName\":\"WIDTH\",\"AttributeValue\":\"120\"},{\"AttibuteName\":\"HEIGHT\",\"AttributeValue\":\"115\"},{\"AttibuteName\":\"MATERIAL DESCRIPTION\",\"AttributeValue\":\"COTTON, WOOD LEGS\"},{\"AttibuteName\":\"MODEL YEAR\",\"AttributeValue\":\"1940\"}]}]"
      }
   ]
}

Upvotes: 4

Views: 1724

Answers (2)

dbc
dbc

Reputation: 116970

The value of your SalesLines property is double-serialized JSON: a string value that contains JSON embedded as a string literal. You would like to deserialize its contents to a final data model in one step.

To see what the data model should look like, you can unescape the JSON as follows:

var json = JToken.Parse(jsonString);

foreach(var token in json.SelectTokens("value[*].SalesLines").ToList())
{
    token.Replace(JToken.Parse((string)token));
}

Console.WriteLine(json);

Then use one of the code-generation tools mentioned in How to auto-generate a C# class file from a JSON object string to generate a data model from the unescaped JSON (I used http://json2csharp.com/):

public class ItemAttribute
{
    public string AttibuteName { get; set; }
    public string AttributeValue { get; set; }
}

public class SalesLine
{
    public string SONumber { get; set; }
    public int LineNum { get; set; }
    public string ItemId { get; set; }
    public List<ItemAttribute> ItemAttributes { get; set; }
}

public class Value
{
    public string documentType { get; set; }
    public string SONumber { get; set; }
    public List<SalesLine> SalesLines { get; set; }
}

public class RootObject
{
    public List<Value> value { get; set; }
}

Finally, apply EmbeddedLiteralConverter<List<SalesLine>> from this answer to How do I convert an escaped JSON string within a JSON object? to Value:

public class Value
{
    public string documentType { get; set; }
    public string SONumber { get; set; }

    [JsonConverter(typeof(EmbeddedLiteralConverter<List<SalesLine>>))]
    public List<SalesLine> SalesLines { get; set; }
}

Now you will be able to deserialize the JSON to RootObject directly:

root = JsonConvert.DeserializeObject<RootObject>(jsonString);

Demo fiddle here.

Upvotes: 4

Alex M
Alex M

Reputation: 147

Create a class that will store your SalesLines, another class that will store ItemAttributes.

SalesLines class should have a property List.

Create a SalesOrder class that will have List as one of the properties.

Then you should be able to deserialize into SalesOrder.

Upvotes: -2

Related Questions