4

The following is my JSON data which happens to be the format supplied by Wikidata, although greatly trimmed down for clarity.

{
"entities": {
    "Q200405": {
        "id": "Q200405",
        "type": "item",
        "claims": "Cheese"
        }
    }
}

I am attempting to access this data within c#. My problem is that the Q200405 is dynamic - it is basically the record number that I am retrieving. For example, another page might give me

{
"entities": {
    "Q123456": {
        "id": "Q123456",
        "type": "item",
        "claims": "Lemon"
        }
    }
}

My best attempt so far was using Json.NET (Newtonsoft) ;

json = "{\"entities\":{\"Q200405\" {\"id\":\"Q200405\",\"type\":\"item\",\"claims\":\"Cheese\"}}}";

var Query = JsonConvert.DeserializeObject<dynamic>(json);
string entities = Query.entities.ToString();

Query = JsonConvert.DeserializeObject<dynamic>(entities);
string entity = Query.Q200405.ToString();

Query = JsonConvert.DeserializeObject<dynamic>(entity);
string id = Query.id.ToString();
string claims = Query.claims.ToString();

This works, but obviously hardcoding Query.Q200405.ToString() is not the ideal solution! I probably should not be doing multiple Deserialize statements to drill down into the data either?

My question is what is the best way to read the above JSON format into a c# program?

Stanislav Kralin
  • 11,070
  • 4
  • 35
  • 58
MortimerCat
  • 829
  • 9
  • 26
  • Seems like you might want some sort of X-path query for json. Is it fair to assume you don't have the id value when you need it? Or is it a parameter in this case? – theMayer Dec 18 '14 at 23:15
  • Once you get the json into .NET I highly recommend you take a look at restsharp: http://restsharp.org/ as far as best practices go. – RandomUs1r Dec 18 '14 at 23:21
  • I do not know the ID. The original sample was a lookup of John Hurt on wikidata.org The ID just happens to be their record number. – MortimerCat Dec 18 '14 at 23:29

2 Answers2

7

Well if you want to put the names into string variables, just use JObject:

string id = "Q200405"; // Or wherever you get that from
string text = "{\"entities...";
var json = JObject.Parse(text);

var claim = json["entities"][id];

string claims = (string) claim["claims"];
string type = (string) claim["type"];
// etc

Basically LINQ to JSON is really what you want here.

EDIT: If you don't know the ID beforehand, you can use:

var json = JObject.Parse(text);
var entities = (JObject) json["entities"];
var entity = entities.Properties().First();
var id = entity.Name;
var claim = (JObject) entity.Value;
string claims = (string) claim["claims"];
string type = (string) claim["type"];
Console.WriteLine(new { claims, type, id });
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • That method works but I do not know the id and it varies between records. However, in my case I could simply use string id = text.Substring(14,7); although that does seem a poor way to do things! – MortimerCat Dec 18 '14 at 23:49
  • @MortimerCat: No, if you don't know the ID but it's the only ID, you can use `json["entities"].First` - that will get the first child token. – Jon Skeet Dec 18 '14 at 23:51
  • Yep, thats great. I had missed those First and FirstOrDefault methods. Thanks. – MortimerCat Dec 18 '14 at 23:59
  • Now that I actually try your latest version I get the error message _Cannot access child value on Newtonsoft.Json.Linq.JProperty_ on the `string claims = (string) claim["claims"];` line – MortimerCat Dec 19 '14 at 11:34
  • @MortimerCat: Okay, will have a look now. – Jon Skeet Dec 19 '14 at 11:52
  • 1
    @MortimerCat: Fixed now - give that a try. (It works for me with your sample JSON) – Jon Skeet Dec 19 '14 at 12:01
  • Thanks for taking the time to do that. I have my program working now :) – MortimerCat Dec 19 '14 at 14:51
2

This is how you can parse it

class Data
{
    public string id { get; set; }
    public string type { get; set; }
    public string claims { get; set; }
}

var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string,Data>>>(json);
Data data = obj["entities"].FirstOrDefault().Value;
Tien Dinh
  • 1,037
  • 7
  • 12