1

I am new to JSON.NET and not sure how to do this.

I have the CartItem class, and I need to implement
GetAllCartItemsFromArbitraryJson(string jsonStr), as follows:

class CartItem {
  public int Id;
  public int Qty;
}

List<CartItem> items = GetAllCartItemsFromArbitraryJson(jsonStr);

All I know is jsonStr contains one or more cartitems somewhere (I don't know how deep), eg.

{
  ... : {
    "cartitems": [{
        "id": "1",
        "qty": "1"
      },{
        "id": "2",
        "qty": "5"
      }
    ]
  },
  ... : {
    ... : {
      ...,
      "cartitems": [{
          "id": "10",
          "qty": "2"
        }
      ]
    }
  }
}

This function needs to collect all the cartitems and put it in List<CartItem>

List<CartItem> GetAllCartItemsFromArbitraryJson(string jsonStr) {
  JObject json = JObject.Parse(jsonStr);
  // then what...?
}

So the List<CartItem> will contains:

Id  Qty
1   1
2   5
10  2

How would you do it in C#?

Aximili
  • 28,626
  • 56
  • 157
  • 216
  • if `JObject.Parse(jsonStr)` is successfull, you can access it's properties via your `json` object.But if the `cartItems` were serialized as part of an object graph, most convenient way would to deserialize the whole graph and then access your desired properties. – Amit Kumar Ghosh Jul 16 '15 at 05:43
  • @YTAM: No, as you can see in the example. Amit: You're saying I need a recursive function? I tried, but I don't understand how to loop through JToken etc – Aximili Jul 16 '15 at 06:17
  • Use [`SelectTokens`](http://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm) and `ToObject`, like so: `var items = json.SelectTokens("..cartitems[*]").Select(t => t.ToObject()).ToList();` – dbc Jul 16 '15 at 06:29
  • Brian, thanks for the "duplicate" but it is completely different. The answer to my question is only one line (dbc's is close but won't work). I'll post it if this can be reopened. – Aximili Jul 16 '15 at 07:22

2 Answers2

4

This is a solution that works:

List<CartItem> GetAllCartItemsFromArbitraryJson(string jsonStr) {
  JObject json = JObject.Parse(jsonStr);

  return json.Descendants().OfType<JProperty>()  // so we can filter by p.Name below
             .Where(p => p.Name == "cartitems")
             .SelectMany(p => p.Value)           // selecting the combined array (joined into a single array)
             .Select(item => new CartItem {
                 Id  = (int)item["id"],
                 Qty = (int)item["qty"]
             }).ToList();
}

Hope it helps someone.
I am new to JSON though, got that by trial & error. So let me know if it can be improved :)

Aximili
  • 28,626
  • 56
  • 157
  • 216
1

Parse to dynamic and iterate through the items.

public List<CartItem> PostAllCartItemsFromArbitraryJson(string jsonStr)
{
    List<CartItem> AllCartItems = new List<CartItem>();
    try
    {
        dynamic BaseJson = JObject.Parse(jsonStr.ToLower());

        CheckForCarts(AllCartItems, BaseJson);
    }
    catch (Exception Error)
    {
    }

    return AllCartItems;
}

private void CheckForCarts(List<CartItem> AllCartItems, dynamic BaseJson)
{
    foreach (dynamic InnerJson in BaseJson)
    {
        if (InnerJson.Name == "cartitems")
        {//Assuming this is an [] of cart items
            foreach (dynamic NextCart in InnerJson.Value)
            {
                try
                {
                    CartItem FoundCart = new CartItem();
                    FoundCart.Id = NextCart.id;
                    FoundCart.Qty = NextCart.qty;
                    AllCartItems.Add(FoundCart);
                }
                catch (Exception Error)
                {
                }
            }
        }
        else if (InnerJson.Value is JObject)
        {
            CheckForCarts(AllCartItems, InnerJson.Value);
        }
    }
}

public class CartItem
{
    public int Id;
    public int Qty;
}

For your sample input this generates:

[{"Id":1,"Qty":1},{"Id":2,"Qty":5},{"Id":10,"Qty":2}]

Brian from state farm
  • 2,825
  • 12
  • 17
  • 1
    +1 Thank you Brian! It works for the sample JSON. But it doesn't work for some of the real JSONs because "cartitems" may also be in a JArray (Your code only checks for JObject). Anyway, I have found a simpler LINQ solution that works (so far). Thanks again! – Aximili Jul 17 '15 at 01:11