28

I am faced with a problem. I want to deserialize a complex JSON response from a server, but I only need one part of it.

Here is an example:

{
 "menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
 }
}

I also used Csharp2json to get the class objects that I need, I just modified the menu class according to my needs :

    public class Menuitem
{
    public string value { get; set; }
    public string onclick { get; set; }
}

public class Popup
{
    public IList<Menuitem> menuitem { get; set; }
}

public class Menu
{
    public Popup popup { get; set; }
}

public class RootObjectJourney
{
    public Menu menu { get; set; }
}

Now, how do I deserialize if I only need the popup value and his children?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
A. Silva
  • 629
  • 1
  • 6
  • 16
  • Why don't you serealise all the response and select only the Popup? Deserealising of all the response is just slightly more expensive than needed in your case – Kirhgoph Jun 22 '17 at 14:02
  • 3
    What you have should *already* do what you have described. What happens when you run it through the deserializer? i.e. `var root = JsonConvert.DeserializeObject(json); var menuitems = root.menu.popup.menuitem;` ? – Marc Gravell Jun 22 '17 at 14:03
  • In this case I would deserialize all the thing. But it is only a simplification of my actual Json. Do a Get request on this url to get the actual json : http://transport.opendata.ch/v1/connections?from=lausanne&to=fribourg It is extremly complicated and long. @MarcGravell It says "Object reference not set to an instance of an object." – A. Silva Jun 22 '17 at 14:08
  • 2
    @A.Silva then your cut down model is not a match for the actual data; I can't tell you where, because the JSON you have linked to has nothing to do with the model you've provided – Marc Gravell Jun 22 '17 at 14:33
  • @MarcGravell, maybe I'm not understanding that error at 100 %. – A. Silva Jun 22 '17 at 14:52
  • I believe you can do the following: `root.menu.popup = JsonConvert.DeserializeObject(json);` – Ingenioushax Jun 22 '17 at 15:53

4 Answers4

34

You can actually utilize the Linq namespace of the NewtonSoft.Json and modify your code little bit to get only the "popup" elements from the JSON.

your class structure remains the same. Make sure you use the namespace(s)

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

then in your code once you have the JSON string with you, you can use the "JObject" static method "Parse" to parse the JSON, like

   var parsedObject = JObject.Parse(jsonString);

This will give you the JObject with which you can access all your JSON Keys just like a Dictionary.

var popupJson = parsedObject["menu"]["popup"].ToString();

This popupJson now has the JSON only for the popup key. with this you can use the JsonConvert to de- serialize the JSON.

var popupObj = JsonConvert.DeserializeObject<Popup>(popupJson);

this popupObj has only list of menuitems.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • 1
    Urgh, that roundtrips from string to json-object to string to Popup object. That's likely going to be more expensive than just taking the whole bunch. – jessehouwing Dec 03 '18 at 12:40
  • 3
    What you want to do to convert from JObject to a custom class is this: https://stackoverflow.com/a/12208692/736079. – jessehouwing Dec 03 '18 at 12:43
7

If you do not use Newtonsoft and are using System.Text.Json in .NET Core, you can use this:

var post = JsonDocument.Parse(stringifiedJson);
var cat = post.RootElement.GetProperty("category").GetString();

You see GetString here to cast the value to string, there are other overloads available to cast the json value to Int32 etc.

Hamid Mosalla
  • 3,279
  • 2
  • 28
  • 51
6

.NET 5+

The solution is very simple:

using System.Text.Json;

var doc = JsonDocument.Parse(response.Content);
var popupJson= doc.RootElement.GetProperty("menu").GetProperty("popup");
user3292624
  • 180
  • 2
  • 10
5

If the intend is to deserialize only one property, I generally perefer to use JsonPath due to its flexibility. Please check the code below

var jsonQueryString = "{ 'firstName': 'John',
 'lastName' : 'doe',
 'age'      : 26,}";
JObject o = JObject.Parse(jsonQueryString);
JToken token= o.SelectToken("$.age");   
Console.WriteLine(token);

If your Json is complex, you can use power of JsonPath. you can check https://support.smartbear.com/readyapi/docs/testing/jsonpath-reference.html#examples for JsonPath detailed documentation and examples.

I also included example below for further usage information:

JObject o = JObject.Parse(@"{
        'store': {
            'book': [
            {
                'category': 'history',
                'author': 'Arnold Joseph Toynbee',
                'title': 'A Study of History',
                'price': 5.50
            },
            ...
            ]
        },
        'expensive': 10
        }");
        //gets first book object
        Console.WriteLine(o.SelectToken("$..book[0]"));
        //get first book's title
        Console.WriteLine(o.SelectToken("$..book[0].title"));

        // get authors of the books where the books are cheaper then 10 $
        foreach (var token in o.SelectTokens("$..[?(@.price < 10)].author"))
            Console.WriteLine(token);
Derviş Kayımbaşıoğlu
  • 28,492
  • 4
  • 50
  • 72