selecting the first 2 FIELDS in a JSON OBJECT - c#

I have some JSON that looks like this:
{
"innerObj1": {
"1. Information": "unimportant"
},
"innerObj2": {
"2017-09-19 16:00:00": {
"number1": "75.4500"
},
"2017-09-19 15:55:00": {
"number2": "75.4200"
}
}
}
Not sure why innerObj2 is not returned as an array (this is from an api) but I have to get number1 and number2 returned as an array of strings. Note that 2017-09-19 16:00:00 and 2017-09-19 15:55:00 are subject to change, so I can't hardcode the selection of those objects in C#. I was thinking of possibly using LINQ, but I'm not sure how. I've really only used them with JSON arrays.

Assuming you are using Json.Net, you can get the values of the innermost properties into an array like this, without needing to know the names of them:
JObject obj = JObject.Parse(json);
string[] numbers = ((JObject)obj["innerObj2"]).Properties()
.SelectMany(jp => ((JObject)jp.Value).Properties())
.Select(jp => (string)jp.Value)
.ToArray();
Fiddle: https://dotnetfiddle.net/5sLy6M
Or, a simpler alternative which does the same thing using SelectTokens with a JSONPath wildcard expression:
string[] numbers = obj.SelectTokens("innerObj2.*.*")
.Select(jt => (string)jt)
.ToArray();
Fiddle: https://dotnetfiddle.net/CyRQ9T

Related

How to get the names of all properties (without their values) in a json object?

I have a json object, a string, that contains some properties and their values. Say I never know what comes in my json object, how can I loop though it and get what properties it contains? For example:
{
"aaaa": 1,
"bbbb": "qwerty",
"ccc": 21.22
}
How do I collect aaa, bbb and ccc? Once again, I don't want their values, I just want the name of the properties.
It's as simple as this:
var json = #"{ ""aaaa"": 1, ""bbbb"": ""qwerty"", ""ccc"": 21.22 }";
var jobject = Newtonsoft.Json.Linq.JObject.Parse(json);
var names = jobject.Root.Cast<JProperty>().Select(x => x.Name).ToArray();
That gives:
aaaa
bbbb
ccc
Deserialize the json to Dictionary using JsonConvert
Note: This will work if the key are always unique
var result = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonString);
Console.WriteLine($"{string.Join(",", result.Keys)}");
just in one line
IEnumerable<string> names = JObject.Parse(json).Properties().Select(x => x.Name);
this will include the names of nested objects properties
IEnumerable names = JObject.Parse(json).Descendants().OfType<JProperty>()
.Select(x => x.Name);

Splitting of values in a JSON array

I have my json ["[\"~:bbl:P5085\",\"~:cosco:NoTag\"]"] coming in
options.Type1.Values()
I am trying to keep only the values coming with bbl so from above I want to keep P5085 and remove all, there can be multiple bbl values in here and I need to keep all. I tried the below code but its not working. The splitting gives me
P5085","~:cosco
I dont understand what wrong am i doing in below code. Can someone provide the fix here?
private void InitializePayload(JsonTranslatorOptions options)
{
_payload.Add("ubsub:attributes", _attributes);
_payload.Add("ubsub:relations", _relations);
JArray newType = new JArray();
foreach (JValue elem in options.Type1.Values())
{
if (elem.ToString().Contains("rdl"))
{
string val = elem.ToString().Split(":")[1];
newType.Add(val);
}
}
_payload.Add("ubsub:type", newType);
}
Try this:
var input = "['[\"~:bbl:P5085\",\"~:cosco:NoTag\"]']";
var BBLs_List = JArray.Parse(input)
.SelectMany(m => JArray.Parse(m.ToString()))
.Select(s => s.ToString().Split(":"))
.Where(w => w[1] == "bbl")
.Select(s => s[2])
.ToList();
As I explain in the comments this isn't JSON, except at the top level which is an array with a single string value. That specific string could be parsed as a JSON array itself, but its values can't be handled as JSON in any way. They're just strings.
While you could try parsing and splitting that string, it would be a lot safer to find the actual specification of that format and write a parser for it. Or find a library for that API.
You could use the following code for parsing, but it's slow, not very readable and based on assumptions that can easily break - what happens if a value contains a colon?
foreach(var longString in JArray.Parse(input))
{
foreach(var smallString in JArray.Parse(longString))
{
var values=smallString.Split(":");
if(values[1]=="bbl")
{
return values[2];
}
}
}
return null;
You could convert that to LINQ, but that would be just as hard to read :
var value=JArray.Parse(input)
.SelectMany(longString=>JArray.Parse(longString))
.Select(smallString=>smallString.Split(":"))
.Where(values=>values[1]=="bbl")
.Select(values=>values[2])
.FirstOrDefault();

C# find JSON value based only on Key name through multiple levels of array

I have a variety of input JSON formatted data which all contain a particular key-name terminalSize. This is the only piece I know. The total number of JSON trees or the exact depth of terminalSize inside the JSON tree will forever be an unknown and subject to change.
I'm looking for a C# solution to loop through every child of the JSON string and find terminalSize then fetch the value.
I've tried this with success but it will only work if terminalSize is in the first level of the JSON:
var list = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(jsonString);
var dict = list.SelectMany(d => d).ToDictionary(p => p.Key, p => p.Value);
var terminal = dict["terminalSize"];
Example 1.
{
"status": "success",
"data": {
"terminalSize": 3766505.46,
"totalTerminalSize": 3766505.46
},
"message": null
}
Example 2.
{
"lastUpdated": 1588020678,
"terminalData": {
"terminalSize": "451679852",
"totalTerminalSize": "2100000000"
},
"terminalValueSeries": {
"8x7": 2.33,
"8x6": 3.73,
"8x5": 4.49,
"8x4": 3.68,
"8x3": 13998,
"8x2": 274936,
"8x1": 5.09
}
}
Example 3.
{
"terminalSize": "492612346.17",
"terminalStatus": "online"
}
You can parse your JSON to a JToken, then use SelectToken with the recursive descent JsonPath operator .. to get the terminalSize anywhere in the JSON:
var terminalSize = (double?) JToken.Parse(json).SelectToken("$..terminalSize");
Fiddle: https://dotnetfiddle.net/5ziYbP
If there might be multiple terminalSize keys in the JSON, for example if you had an array of terminals, you can use SelectTokens instead and put the terminal sizes into a Dictionary keyed by path:
var sizes = JToken.Parse(json4)
.SelectTokens("$..terminalSize")
.ToDictionary(t => t.Path, t => (double)t);
Fiddle: https://dotnetfiddle.net/ivSM88
You could also use linq and filter the JProperty collection based on JProperty.Name. For example
var result = JObject.Parse(jsonString)
.DescendantsAndSelf()
.OfType<JProperty>()
.Single(x=>x.Name.Equals("terminalSize"))
.Value;
You may parse your JSON into JObject, then recursively go through all properties and sub objects to find a terminalSize value. There is no need to deserialize the entire JSON into specific object
var json = JObject.Parse(jsonString);
var result = GetTerminalSize(json);
double GetTerminalSize(JObject input)
{
foreach (var property in input.Properties())
{
if (property.Name == "terminalSize")
return property.Value.Value<double>();
if (property.Value.Type == JTokenType.Object)
return GetTerminalSize((JObject) property.Value);
//not sure, if the is a need to handle an array
if (property.Value.Type == JTokenType.Array)
foreach (var item in (JArray) property.Value)
return GetTerminalSize((JObject) item);
}
return 0;
}
It returns a correct value for all 3 examples

Getting the values from this specific JSON

I'm trying to get all of the "last" values from this JSON here:
{"btc":{
"usd": {
"bitfinex": {
"last": "1191.60",
"volume": "1.99324e+7"
},
"bitstamp": {
"last": "1193.06",
"volume": "8.73693e+6"
},
"btce": {
"last": "1174.27",
"volume": "6.03521e+6"
}
}
}
But for some reason I can only access "btc" and "usd". I can't get anything out of it including the "last" values. Here is the code i'm using:
private string GetPrice()
{
WebClient wc = new WebClient();
var data = wc.DownloadString("http://preev.com/pulse/units:btc+usd/sources:bitfinex+bitstamp+btce");
JObject o = JObject.Parse(data);
string response = o["btc"].ToString();
return response;
}
If I change it to:
o["last"].ToString();
It just doesn't return anything. Can someone please provide me with a solution? I also tried making a key/value dict out of it and looping over each pair. Did not work.
The JObject structure is similar to a class with properties, so the first-level indexer ["btc"] returns another object that you have to query for its own properties ["usd"]
You can also opt for using JObject.SelectToken, generally not a bad idea. Other answers have shown how to chain the indexers but that's hard to read and maintain. Instead you can do:
jObj.SelectToken("btc[0].usd[0].bitstamp[0].last").ToString();
Further you can use the power of this syntax for other queries:
// a list o all the 'last' values
jObj.SelectTokens("btc.usd.*.last").Select(t=>t.ToString()).ToList();
Another advantage, if you're building a more complex system, is that you could put the queries in a config file or attributes etc to make them more manageable or deploy logic changes without rebuilding.
Yet another approach would be to build your own class structure and deserialize your json into it, so you have strongly typed values (double instead of string for the values for example)
public class btc {
public usd usd {get;set;}
}
public class usd....
var btcLoaded = JsonConvert.DeserializeObject<btc>(jsonString);
var lastBitstamp = btc.usd.bitstamp.last;
Use: o["btc"]["usd"]["bitfinex"]["last"].ToString() to get the 'last' value of 'bitfinex'.
After parsing the JSON whenever you index the o variable you are indexing from the root of the JSON. In order to access nested properties like 'last' you will need to index into the next level of the JSON as such:
var bitfinex = o["btc"]["usd"]["bitfinex"]["last"].ToString();
var bitstamp = o["btc"]["usd"]["bitstamp"]["last"].ToString();
var btce = o["btc"]["usd"]["btce"]["last"].ToString();
To reduce the repetition you could iterate over the properties under the btc.usd field.
if u want to all last values use this..
decimal[] lastValues = obj.SelectTokens("$..last").ToArray()
.Select(a => a.Parent.ToObject<decimal>()).ToArray();
if u want to dictionary, use this..
var dictionary = obj["btc"]["usd"].Select(a =>
new
{
Key = ((JProperty)a).Name,
Value = a.First["last"].ToObject<decimal>()
})
.ToDictionary(a => a.Key, a => a.Value);

How to convert a JSON array to an array of string values

I'm try to parse some JSON like this:
{
"results": [
"MLU413843206",
"MLU413841098",
"MLU413806325",
"MLU413850890",
"MLU413792303",
"MLU413843455",
"MLU413909270",
"MLU413921617",
"MLU413921983",
"MLU413924015",
"MLU413924085"
]
}
All is fine until I try to obtain the values themselves, for example:
// The JSON is shown above
var jsonResp = JObject.Parse(json);
var items = jsonResp["results"].Children();
I don't know how to obtain the values, each converted to string. Does somebody know how to do this?
You're halfway there. You can use the Select() method in the System.Linq namespace to project the IEnumerable<JToken> returned from the Children() method into an IEnumerable<string>. From there you can loop over the values using foreach, or put the values into a List<string> using ToList() (or both).
string json = #"
{
""results"": [
""MLU413843206"",
""MLU413841098"",
""MLU413806325"",
""MLU413850890"",
""MLU413792303"",
""MLU413843455"",
""MLU413909270"",
""MLU413921617"",
""MLU413921983"",
""MLU413924015"",
""MLU413924085""
]
}";
JObject jsonResp = JObject.Parse(json);
List<string> items = jsonResp["results"].Children()
.Select(t => t.ToString())
.ToList();
foreach (string item in items)
{
Console.WriteLine(item);
}
Fiddle: https://dotnetfiddle.net/Jcy8Ao

Categories