Querying a complex Json with Linq - c#

I would like to make a Linq query in a json string.
little info about what i'm trying to do. At work we have a web based schedule system which don't have a support for windows 8 and windows phone 8 app. That is why I decided to make one. Using HttpClient I get an http string which I then convert to xml then Json. As you can see from the (Link below, the 'TheWholeJsonString.json' file) the property name and JSON object name is not informative and the JSON file is complicated. That is why I decided to extract some of the values from the JSON string and write a totally new JSON file that include the extracted JSON values in a more informative way.
The [tr] array in the original JSON file have several JSON Objects. Inside the 'VeryShorten.json' file in the linked folder you can see the structure of one of those objects (OBS! there is objcet with different structure). The only thing I hide is the Name and E-Mail address of RL ppl.
I also attached 'ShortenVersion.json' which is only a shorten version of the whole json string, just to make it easy to handle.
Json data sample
{
"#class": "odd",
"td": [
{
"#class": "user",
"#onmouseover": "userInfo('149');",
"#onmouseout": "userInfo(0);",
"#onmousemove": "moveSlotInfo();",
"#text": " ",
"a": {
"#href": "Name3#dreamnet.com",
"#text": "Name3"
}
},
.
.
.
In C# if i try the following code (which is not Linq)
var jObject = JObject.Parse(jString); //jString is 'TheWholeJsonString.json' file in the attached link
var jObj = jObject["tbody"]["tr"][8];
var gh = jObj.Value<JToken>("td").Children().First().Value<JToken>("a").Value<string>("#text");
i can get the value of '#text' which is *'Name3'.
However if i try the following code (Linq version):-
var jObject = JObject.Parse(jString);
var jCollection = jObject["tbody"]["tr"].Children();
var test = from userToken in jCollection
where
userToken.Value<JToken>("td")
.Children()
.First()
.Value<JToken>("a")
.Value<string>("#text")
.Contains("Name3")
select (string)userToken["#text"];
foreach (var item in test)
{
var fgh = item.Type;
}
It will break on the first iteration of foreach loop with the following error msg "Cannot access child value on Newtonsoft.Json.Linq.JValue". I really now what is causing the problem, but i don't know how to solve it. The problem is that not every token inside jCollection have a 'td' object and even if the token have 'td' object it is not Always it have token 'a'. You can see this either in the 'TheWholeJsonString.json' or 'ShortVersion.json' files which i attached in the link.
Hope this will explain more info.
So the question is:- Anyone can help to solve this problem?

You can use SelectTokens method. Notice false as second parameter - don't generate error if element is not found.
var jObject = JObject.Parse(jString);
var trList = jObject["tbody"]["tr"];
string[] names = trList.SelectMany(tr => tr.SelectTokens("td[0].a.#text", false))
.Select(t => t.Value<string>())
.ToArray();

You can easily query with LINQ like this
considering this JSON
{
"items": [
{
"id": "10",
"name": "one"
},
{
"id": "12",
"name": "two"
}
]
}
putting it in a variable called json like this,
JObject json = JObject.Parse("{'items':[{'id':'10','name':'one'},{'id':'12','name':'two'}]}");
you can select all ids from the items where name is "one" using the following LINQ query
var Ids =
from item in json["items"]
where (string)item["name"] == "one"
select item["id"];

Related

Windows.Data.Json keep original order

Im trying to use the Windows.Data.Json (moving away from JSON.NET) to parse JSON from a server but it seems to mix up the order of items when looping (foreach) through the keys.
Is there any way to maintain the original order?
For example:
JSON:
{
"name1": "example",
"name2": "example",
"name3": "example",
"name4": "example"
}
When i do a string print out of the JsonObject it appears to be in the correct order but when i loop through them they get output in a different order.
For example:
foreach(string name in parsedJson.Keys)
{
}
Which outputs in this order
"name3", "name2", "name1", "name4"
When i do a string print out of the JsonObject it appears to be in the correct order but when i loop through them they get output in a different order.
I made a demo and reproduced your problem. After researching, I found JsonObject.Keys is using IDictionary.Keys, which doesn't guarantee the order.If you want to loop through the JObject in correct order I suggest you using Newtonsoft.Json.
You can loop through the JSON Object using following codes:
using Newtonsoft.Json.Linq;
...
String jsonStr = "{\"name1\": \"example\",\"name2\": \"example2\",\"name3\": \"example3\",\"name4\": \"example4\"}";
JObject obj=JObject.Parse(jsonStr);
foreach (JProperty prop in obj.Properties())
{
string key = prop.Name;
var value = prop.Value.ToString();
}

How can I retrieve a json value to a property whose path is dynamic

How to fetch "full_name_ac" in the following JSON :-
{
"rows": 10,
"os": "0",
"page": "1",
"total": "1",
"peoples": {
**"123":** {
"url": "http://google.com",
**"id": "123",**
"fname": "Rob",
"lname": "Tom",
"full_name_ac": "Rob Tom"
}
}
}
I can not create model because model is always going to be changed according to "id".
I am trying something like that but not sure how to get the value of full_name_ac
JObject obj = JObject.Parse(data);
I'd recommend you take a look at using JSONPath(s) and use SelectTokens:
JObject obj = JObject.Parse(data);
var names = obj.SelectTokens("$.peoples.*.full_name_ac");
var allNamesAsCsv = String.Join(",", names.Values<string>());
Of course, if you always know that there will always be just one, you can use SelectToken:
var onlyMatchObject = obj.SelectToken("$.peoples.*.full_name_ac");
var onlyMatch = first.Value<string>();
Use Json.Net. try to use dyanamic
dynamic stuff = JsonConvert.DeserializeObject(YOUR-JSON_STRING);
string name = stuff.peoples.123.full_name_ac;
See this link for more info:Deserialize JSON into C# dynamic object?
model is always going to be changed according to "id".
If your model is always changes then you have create one model which contains id and string. String object is a json string of fields. So that you can check Id and it's model fields. so you can compare that fields with json.
"field" :
{
"id" : 123
"fields" :
{
"fname":"string",
"full_name_ac":"string"
}
}
Create json something like above and include this json in your json. When you deserialize your main json you can compare fields. I thing from above you will get some basic idea.
If your model is dynamic then there is only one option i.e. you have
to create a json something like above which contains fields. So that you can
compare that fields with your actual json value.
Maybe you can use a Regex and some basic text parsing, to identify the "full_name_ac" property, and subtract the value, something like:
// just an example, untested
string jsonText = "{...}";
int startIndex = jsonText.indexOf(#"""full_name_ac"":");
int stopIndex = jsonText.indexOf(startIndex, "}");
string value = jsonText.substring(startIndex, stopIndex);
Fetch the value of required token of the deserialized object (in your case obj.peoples has first token as "123" and first token of "123" is the object which has the required properties) and get the required property i.e. full_name_ac from it.
dynamic obj = JObject.Parse(jsonText);
var value = obj.peoples;
var tokenPeople = ((Newtonsoft.Json.Linq.JContainer)obj.peoples).First.First;
string peopleJson =tokenPeople.ToString();
dynamic people = JObject.Parse(peopleJson);
string full_name_ac = people.full_name_ac;
Following line will help you to get the value of full_name_ac
var full_name_ac = obj.SelectToken("peoples.123.full_name_ac").ToString();
using JObject.Parse(jsonString) AND get First element
// Id is dynamic , so parse and get first element
string dynamicName = (string)JObject.Parse(data)["peoples"].Children().First().Children().First()["full_name_ac"];

Querying JSON from C#

I'm trying to retreive a json item from a json string,this is my json for example:
{
"users":{
"john":{
"password":"0506777031",
"level":1
},
"doe":{
"password":"john",
"level":1
},
"dasda":{
"password":"das",
"level":"1"
},
"zuri":{
"password":"zuri123",
"level":2
}
}
}
I use the json.net library,this is what i've tried so far:
JObject json = JObject.Parse(jsonstring); //this is thr string
JObject match = json["users"].Values<JObject>().Where(m => m["username"].Value<string>() == "itapi" && (m["password"].Value<string>() == "0506777031")).FirstOrDefault();
I'm getting an error on the second line.
This is the error:
Cannot cast Newtonsoft.Json.Linq.JProperty to Newtonsoft.Json.Linq.JToken.
I'm not sure what i'm doing wrong,i will appreciate any help! thanks!
Assuming your question is "What am I doing wrong?", the answer would be
You are trying to typecast what is a JProperty into a JObject (JProperty has a property named Value you can access).
You are not traversing the JSON syntax tree properly.
There is no mention of the "username" within the JSON sample provided.
If the usernames in your example are the property keys (names) "john", "doe", "dasda" and "zuri"... The query you probably want is as follows:
var match = json["users"].Values<JProperty>().Where(m => m.Name == "doe" && m.Value["password"].ToString() == "john").FirstOrDefault();
EDIT: Alternatively, if the username is that key, you can use the direct lookup and assign to the variable match only if the password matches the one you are trying to compare. Also the following version will return the JObject and not the JProperty as it seems you originally wanted. This should also be more efficient.
JObject match;
var temp = json["users"]["doe"];
if(temp["password"].ToString() == "john")
{
match = temp.ToObject<JObject>();
}
Shouldn't it be using square brackets for "users"?
{
"users":[
"john":{
"password":"0506777031",
"level":1
},
"doe":{
"password":"john",
"level":1
},
"dasda":{
"password":"das",
"level":"1"
},
"zuri":{
"password":"zuri123",
"level":2
}
]
}

Capture json data from Steam API

So I what I am trying to do is capture/extract specific data from Steams API for dota2 heroes. I am using C# to do this with this method.
https://api.steampowered.com/IEconDOTA2_570/GetHeroes/v0001/?key=2D13D618DA712015812E970165632F02&language=en_us
{
"result": {
"heroes": [
{
"name": "npc_dota_hero_antimage",
"id": 1,
"localized_name": "Anti-Mage"
},
]
}
This is the code I have been trying with:
WebClient c = new WebClient();
var data = c.DownloadString("https://api.steampowered.com/IEconDOTA2_570/GetHeroes/v0001/?key=2D13D618DA712015812E970165632F02&language=en_us");
JObject o = JObject.Parse(data);
string heroname = (string)o["name"];
But it only returns an error saying the value of "heroname" is null.
Any ideas?
o is going to be an object that contains one key: result. o["result"] will in turn contain a key called heroes. o["result"]["heroes"] is an array of objects. So o["result"]["heroes"][0] will be the first item, and o["result"]["heroes"][0]["name"] is the name from the first item.

Can I LINQ a JSON?

This is the JSON I get from a request on .NET:
{
"id": "110355660738",
"picture": {
"data": {
"url": "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-prn2/1027085_12033235063_5234302342947_n.jpg",
"is_silhouette": false
}
}
}
and I'd like to catch the field "url", using (maybe?) LINQ. I do many request as this, that differents a bit. So I won't to create a C# Class and deserialize it every time.
Is it a way to extract a single field? Thank you!
No need for Linq, just use dynamic (using Json.Net)
dynamic obj = JObject.Parse(json);
Console.WriteLine((string)obj.picture.data.url);
Linq version would not be much readable
JObject jObj = JObject.Parse(json);
var url = (string)jObj.Descendants()
.OfType<JProperty>()
.Where(p => p.Name == "url")
.First()
.Value;
Documentation: LINQ to JSON
I would not recommend LINQ. I would recommend a JSON library such as newtonsoft.json.
So you can do this:
string json = #"{
""Name"": ""Apple"",
""Expiry"": "2008-12-28T00:00:00",
""Price"": 3.99,
""Sizes"": [
""Small"",
""Medium"",
""Large""
]
}";
JObject o = JObject.Parse(json);
string name = (string)o["Name"];
// Apple
JArray sizes = (JArray)o["Sizes"];
string smallest = (string)sizes[0];
// Small
Note:- this code has been copied from the samples present on the project site
http://james.newtonking.com/pages/json-net.aspx
In a bind you could always deserialize the JSON and serialize it to XML, and load the XML in a XDocument. Then you can use the classic Linq to XML. When you are done take the XML, deserialize it, and serialize it back to JSON to JSON. We used this technique to add JSON support to an application that was originally built for XML, it allowed near-zero modifications to get up and running.
You can easily query with LINQ like this
considering this JSON
{
"items": [
{
"id": "10",
"name": "one"
},
{
"id": "12",
"name": "two"
}
]
}
let's put it in a variable called json like this,
JObject json = JObject.Parse("{'items':[{'id':'10','name':'one'},{'id':'12','name':'two'}]}");
you can select all ids from the items where name is "one" using the following LINQ query
var Ids =
from item in json["items"]
where (string)item["name"] == "one"
select item["id"];
Then, you will have the result in an IEnumerable list

Categories

Resources