I have a string of Json which looks like this:
{"Linkin Park":{"mbid_id":"f59c5520-5f46-4d2c-b2c4-822eabf53419","artistbackground":
[{"id":"34862","url":
"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-4fcd2d8e4764f.jpg",
"likes":"4"},{"id":"3953","url":
"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-4de522dac2c13.jpg","likes":"1"},{"id":"3954","url":
"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-4de523586c57e.jpg","likes":"1"},{"id":"4251","url":"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-4dea53983f4cf.jpg","likes":"1"},{"id":"30196","url":
"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-4fabb53ba80a3.jpg","likes":"1"},{"id":"52251","url":
"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-5058a071d9782.jpg","likes":"1"},{"id":"52252","url":"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-5058a071d9f41.jpg","likes":"1"},{"id":"52254","url":
"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-5058a0ebd0350.jpg","likes":"1"},{"id":"52255","url":"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-5058a0ebd098b.jpg","likes":"1"},{"id":"63902","url":
"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-50c2f127eeae6.jpg","likes":"1"},{"id":"3951","url":"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-4de521f409aa2.jpg","likes":"0"},{"id":"3952","url":
"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-4de5225cdd595.jpg","likes":"0"},
{"id":"28038","url":"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-4f8ecbd3c004d.jpg","likes":"0"},{"id":"88261","url":"http://assets.fanart.tv/fanart/music/f59c5520-5f46-4d2c-b2c4-822eabf53419/artistbackground/linkin-park-51d1d122f3029.jpg","likes":"0"}]}}
If you did have the time to read all of that, you might see my problem. There are Json nodes which change name depending on what query I send. This time I sent "Linkin Park", and I got nodes named Linkin park. If I then were to send a query of Madonna I would end up with nodes called Madonna.
How would you go about de-serializing this into classes?
You have a few options:
Dictionary
dynamic
JObject, and then deserialize to strongly-typed one node down (assuming the subtree is static in its structure and naming) (this is based on Newtonsoft.JSON)
What library are you using for JSON deserialization?
Example of #1 using Json.NET:
var json = JsonConvert.DeserializeObject<Dictionary<string, StronglyTyped>>(jsonStr);
var data = json.Values.FirstOrDefault();
Example of #3 using Json.NET:
var json = JsonConvert.DeserializeObject<JObject>(jsonStr);
var topProp = json.Properties().FirstOrDefault().Name;
var data = json[topProp].ToObject<StronglyTyped>();
Since you know the query, the simplest solution would be to replace {"%QUERY%":{ with {"MyCommonDeserializableClass":{ before deserializing the string. :-)
But you should make sure that the JSON contains only one object like this. Logically it seems they return the artist name because several artists may match the query.
Related
I have this json object that looks like this below but I can't figure out how to acccess the objects data
I want to access the 5th index like this
jsonContent[5]
error CS0021: Cannot apply indexing with [] to an expression of type 'object'
It looks like an object rather than array. So try jsonContent["5"] or jsonContent["[5]"] instead ?
Here is what is needed, using the JObject library.
var currency = (jsonContent["quotes"] as JObject)["USD"].Value<decimal>();
I thought this question might be ill-formed, so I created a "sister" question that's far more to-the-point, which specific output cited. Please see to:
Querying JSON Nested Arrays with Linq, JSON.NET, C#
If that question gets answered before this one, I'll try to answer this one myself using the information from the other question... :) Thanks!
In a previous question (Picking Out Simple Properties from Hierarchical JSON), I asked how to pick up simple properties from hierarchical JSON. The answer there [pasted as a Linq query at the end of this post] is extremently useful (and, since posting that, I've studied quite a bit about Linq and JSON.NET). So I'm not using this forum because I'm lazy--I use it when I'm really stuck and can't seem to find the answers in the books I have access to.
I'm stumped on how to continue with the example provided by my previous question. This question builds on the previous one, so here (as succinctly as I could express) is what I'd love to learn how to do in a single Linq query.
To recap: I'm working with dynamic JSON like this (it is more complex than the JSON presented in my earlier Part I question because it contains arrays):
{
"Branch1": {
"Prop1A": "1A",
"Prop1B": "1B",
"Prop1C": "1C",
"Branch2": {
"Prop2A": "2A",
"Prop2B": "2B",
"Prop2C": "2C",
"Branch3": [{
"Prop3A": "3A",
"Prop3B": "3B",
"Prop3C": "3C"
}, {
"Prop3D": "3D",
"Prop3E": "3E",
"Prop3F": "3F"
}, {
"Prop3G": "3G",
"Prop3H": "3H",
"Prop3I": "3I"
}]
},
"Branch4": [{
"Prop4A": "4A",
"Prop4B": "4B",
"Prop4C": "4C"
}, {
"Prop4E": "4E",
"Prop4F": "4F",
"Prop4G": "4G"
}, {
"Prop4H": "4H",
"Prop4I": "4I",
"Prop4I": "4I"
}]
}
}
As you can see, the dynamic JSON is composed of hierarchical objects, and these objects are JSON objects, JSON arrays, and JSON properties.
Ultimately, I want to convert this JSON to a List object I can work with in C#. I plan to use that List object to effectively process each JSON branch in document order from the top, down.
Each item in the List collection would be a JObject; each of these objects would have a synthetic "parent" string property that would point back to the branch under which that JObject appears in the original JSON (my examples below explain what I mean by "parent"). [The previous question correctly came up with a solution for this "parent" value, so that's not too relevant to this question... What's new/relevant here is dealing with JArray objects in the JSON...]
The key is that I want each List item object to contain only the string-value properties for the object. For example, Branch1 has string properties Prop1A, 1B, and 1C. Thus, I would want query[0] to contain:
{"Prop1A":"1A","Prop1B":"1B","Prop1C":"1C", Parent:""}
Next, I would want query[2] to contain the string-value properties for Branch2:
{"Prop2A":"2A","Prop2B":"2B","Prop2C":"2C", Parent:"Branch1"}
Next, I would want query[2] to contain the string properties for only Branch3, but because Branch3 is an array of objects, I would want that array to end up together in query[2]:
[
{"Prop3A": "3A","Prop3B": "3B","Prop3C": "3C"},
{"Prop3D": "3D","Prop3E": "3E","Prop3F": "3F"},
{"Prop3G": "3G","Prop3H": "3H","Prop3I": "3I"}
]
Notice that this Branch doesn't yet have a reference to its "Parent"... I'd be happy getting an array in query[2] that looks like the above. (I plan to use dbc's logic to add a "Parent" property to each array element or figure out a way to create a new JObject that contains the array and cites the Parent only once):
[{"Prop3A": "3A","Prop3B": "3B","Prop3C": "3C","Parent":"Branch2"},
{"Prop3D": "3D","Prop3E": "3E","Prop3F": "3F","Parent":"Branch2"},
{"Prop3G": "3G","Prop3H": "3H","Prop3I": "3I","Parent":"Branch2"}
]
So, as you can see:
I would want any JSON branch that is not an array to be inserted as a new JObject in the query result along with only its string properties and a reference to its parent branch.
I would want any JSON branch that is an array to be inserted as a new JObject array in the query result along with only its string properties and a reference to its parent branch.
The trouble I had solving this on my own has to do with figuring out how to create the "if myJsonObject is JArray" condition in Linq and assigning just the string-property properties when the branch is not an array and iterating the array's elements when it is a JArray. I suspect I need to somehow leverage the ? : ternary expression, but I don't exactly know how to do that.
The query from the previous question is here:
var query3 = from o in root.DescendantsAndSelf().OfType<JObject>() // Find objects
let l = o.Properties().Where(p => p.Value is JValue) // Select their primitive properties
where l.Any() // Skip objects with no properties
// Add synthetic "Parent" property
let l2 = l.Concat(new[] { new JProperty("Parent", o.Ancestors().OfType<JProperty>().Skip(1).Select(a => a.Name).FirstOrDefault() ?? "") })
select new JObject(l2); // And return a JObject.
var list3 = query3.ToList();
That code doesn't handle arrays in the way described above.
A suitable and more general answer to this question effectively appears in my related post:
Picking Out Simple Properties from Hierarchical JSON
I am trying to create an object-agnostic Percolator microservice in C#. I can create and map an index passed into my method using a JSON object for the mapping, I can even then register a percolator against the index using the standard NEST query format, such as this:
var percolateResponse = client.RegisterPercolator<dynamic>(query
.Name, p=>p
.Index(index.ActualName)
.Query(q=>q
.Term(t=>t
.OnField("banana")
.Value("green"))));
The problem is, I need to be able to pass in a JSON of the query and I've been trying to use the following code:
var percolateResponse = client.RegisterPercolator<dynamic>(query
.Name, p=>p
.Index(index.ActualName)
.Query(q=>q.Raw(query.Context)));
The JSON that I am passing in is:
{"query":
{"term":
{"banana":
{"value": "green"}
}
}
}
What is happening though, instead of that registering the specified query as a percolator query, it sets the Query value of the RegisterPercolatorRequest to null and basically cancels out the query if it exists.
I have tried a number of different formats of the JSON, and have not found something that the .Query(q=>q.Raw(query.Context)) liked.
Does ANYONE know how to solve this? I have moved closer and closer to a solution to this, but just never quite gotten past this one issue. It is my last remaining roadblock to creating a percolator proxy class. Any help is appreciated. Thanks.
Just for reference, the error I am getting (deep inside the Response object) is this:
[<indexName>] failed to parse query [<queryName>]];
nested: QueryParsingException[[<indexName>] [_na] query malformed,
no field after start_object
I think I have found the solution to what I am trying to do... the above query didn't work, but through some trial and error, I have found out what DOES work to take in an object-agnostic query and register a percolator:
var percolateResponse = client.RegisterPercolator<dynamic>(query
.Name, p => p
.Index(index.ActualName)
.Query(q => q
.SimpleQueryString(sqs=>sqs
.Query(query.Context))));
This creates the Query as a Simple Query String and stores it as such in ElasticSearch, and appears to then work when I try to percolate a document that would match that query!
I've been looking at Dynamic Linq today (installed into VS via NuGet)...but all the examples I have found so far assume OrderBy is to be done on a known property or column name; however I am trying to OrderBy a field which is not strongly typed; but actually a key value of a row object which is derived from a Dictionary; e.g.
class RowValues : Dictionary<string, string>
{
...
}
So the list to be ordered is specifically a list of RowValues objects, filled with Name,Value pairs. For a given list of RowValues, the OrderBy field could by any of keys of the named value pairs entries (fyi: I want the orderby field to be specified in an xml config file ultimately so the ordering can be changed without re-deployment of binaries etc).
I've got a hunch the solution lies in writing a custom ordering function passed to the OrderBy??? This function would obviously know how to get a specific value from the RowValues object given a field name from the xml config....?? The answers I have seen so far show passing a string which contains a custom order by clause into the OrderBy, which is close to where I want to be, but how in my case would the runtime know where to find the fields referred to in the OrderBy string??
Input will be very much appreciated, or have I completely misunderstand the Dynamic Linq functions?
If you're using dynamic LINQ, it would just be:
var sortColumn = GetConfigValue(...);
var sorted = RowValues.OrderBy(sortColumn);
You could of course use a concatenated string to create a multiple sort ("column1, column2 DESC"). As far as I'm aware, there's no custom sort function unless you're using regular LINQ.
Also, I would make sure you know the performance characteristics of Dynamic LINQ.
Edit:
Is this what you're looking for? This will order it based on the value of the "Key" entry in the dictionary. If you need multiple sort by-s, you can use it in a loop with .ThenBy()
void Main()
{
List<RowValues> v = new List<RowValues>();
var key = "Key"; //GetFromConfig();
var v1 = new RowValues();
v1.Add("Key", "1");
v1.Add("3", "5");
var v2 = new RowValues();
v2.Add("Key", "3");
v2.Add("2", "2");
var v3 = new RowValues();
v3.Add("Key", "2");
v3.Add("2", "2");
v.Add(v1);
v.Add(v2);
v.Add(v3);
v.OrderBy(r => r[key]).Dump();
}
class RowValues : Dictionary<string, string>
{
}
Kyle, thanks again. Apologies for late reply, I have moved on from this issue now but out of interest and courtesy I wanted to come back and agree your code is much closer to where I wanted to get to, but we have lost the dynamic linq aspect. So, where you are calling the OrderBy and ordering on the key, I would want to pass a string containing the order command e.g "r[key] desc". The reason being I would want to leave the determination as to which direction to order until runtime. I suspect ths would be accomplished using an expression tree possibly? e.g: here
I am calling a sharepoint service /_vti_bin/usergroup.asmx from my silverlight app. In that the method GetAllUserCollectionFromWeb() returns the XML string. I need to iterate through that XML string to get the required data. But the LINQ to XML in this scenario is not working, as it is working when loading the XML file and getting the req data. How to do the similar functionality of LINQ to SQL with an XML string?
Sample code:
string str = #"<LanguageDetails>
<UserNode>
<Lang>
English
</Lang>
</UserNode>
</LanguageDetails>";
Need to handle the similar string and iterate to read the value using LINQ to XML.
You mean something like this?
string str = #"<LanguageDetails>
<UserNode>
<Lang>
English
</Lang>
</UserNode>
</LanguageDetails>";
XElement xLanguageDetails = XElement.Parse(str);
foreach (XElement xUserNode in xLanguageDetails.Elements("UserNode"))
{
}
In almost all cases where you return no rows when doing LINQ to XML queries, the reason is because there is a namespace in your XML. Check the root nodes to see if there are any namespaces and include them in your LINQ queries.