Simplify looking up nested Json values with Json.NET - json

I use the Facebook's graph Api to get posts from a Facebook page I administer. To get a url to the full size picture of a post I included the "attachments" field. the JSon obtained is as follows:
{
"data": [
{
"message": "Using Facebook's Graph Api to get Testdrive's news from the Facebook page on to the website. So this post will be visible in a minute at the website as well. Cool!",
"link": "https://www.facebook.com/TestdriveDressage/photos/a.493612667417831.1073741827.493607594085005/681741335271629/?type=1&relevant_count=1",
"picture": "https://scontent-b.xx.fbcdn.net/hphotos-xpf1/v/t1.0-9/s130x130/10394069_681741335271629_2094079936902591674_n.png?oh=85676b5ec301e78bd15e2cabde9b8f8f&oe=5561C419",
"id": "493607594085005_681741408604955",
"created_time": "2015-02-03T15:58:54+0000",
"attachments": {
"data": [
{
"description": "Using Facebook's Graph Api to get Testdrive's news from the Facebook page on to the website. So this post will be visible in a minute at the website as well. Cool!",
"media": {
"image": {
"height": 666,
"src": "https://scontent-b.xx.fbcdn.net/hphotos-xpf1/v/t1.0-9/s720x720/10394069_681741335271629_2094079936902591674_n.png?oh=ac58799007b9b909ebc9f0ca762fd6c6&oe=554BD8A3",
"width": 720
}
},
"target": {
"id": "681741335271629",
"url": "https://www.facebook.com/TestdriveDressage/photos/a.493612667417831.1073741827.493607594085005/681741335271629/?type=1"
},
"title": "Timeline Photos",
"type": "photo",
"url": "https://www.facebook.com/TestdriveDressage/photos/a.493612667417831.1073741827.493607594085005/681741335271629/?type=1"
}
]
}
}, ... next "post"
Now I use Json.Net in c£ like this to get post.data.attachments.media.image.src:
FacebookClient fbClient = new FacebookClient(HttpContext.Current.Session[SessionFacebookAccessToken].ToString());
JObject posts = JObject.Parse(fbClient.Get(String.Format("/{0}/posts?fields=message,picture,link,attachments", FacebookPageId)).ToString());
JArray postItems = (JArray)posts["data"];
List<NewsItem> newsItems = new List<NewsItem>();
NewsItem ni;
foreach (JToken item in postItems.Where(item => item["message"] != null))
{
ni = new NewsItem { Message = item.Value<String>("message"), DateTimeCreation = item.Value<DateTime?>("created_time"), Link = item.Value<String>("link"), Thumbnail = item.Value<String>("picture") };
JToken attachments = item["attachments"];
// "Browse" attachments node for possible links to larger image...
if (attachments != null)
{
JToken attachmentsData = attachments["data"];
if (attachmentsData != null)
{
JToken attachmentsArray = attachments["data"];
if (attachmentsArray != null)
{
JToken media = attachmentsArray[0];
if (media != null)
{
JToken media2 = media["media"];
if (media2 != null)
{
JToken image = media2["image"];
if (image != null)
{
ni.Image = image.Value<String>("src");
}
}
}
}
}
}
newsItems.Add(ni);
}
Is there anyway I can simplify this?
It feels a bit odd and I'm not so happy with it...I tried already item["attachments"]["data"]["media"]["image"]["src"] but doesn't work because there's an array at "data" I guess
Any advice or explanation is appreciated.

Try using SelectToken(). You can specify a path to the value you want. If any item along the path is null, the whole expression will be null. This can greatly simplify your code. I've added a fiddle to demonstrate.
string url = (string)item.SelectToken("attachments.data[0].media.image.src");
Fiddle: https://dotnetfiddle.net/YL6t5c

Related

Remove a specific JSONObject from JSONArray in groovy

Say I have a JSON request payload like
{
"workflow": {
"approvalStore": {
"sessionInfo": {
"user": "baduser"
},
"guardType": "Transaction"
}
}
}
I get the value of user via
def user = req.get("workflow").get("approvalStore").get("sessionInfo").get("user")
Now, I get a RestResponse approvalList which I store as list and return to caller as return approvalList.json as JSON. All well so far.
Suppose the response (approvalList.json) looks like below JSONArray -
[
{
"objId": "abc2",
"maker": "baduser"
},
{
"objId": "abc1",
"maker": "baduser"
},
{
"objId": "abc4",
"maker": "gooduser"
}
]
Question : How may I filter the approvalList.json so that it doesn't contain entries (objects) that have "maker": "baduser" ? The value passed to maker should essentially be the user variable I got earlier.
Ideal required output -
It's not entirely clear if you always want a single object returned or a list of objects but using collect is going to be the key here:
// given this list
List approvalList = [
[objId: "abc2", maker: "baduser"],
[objId: "abc1", maker: "baduser"],
[objId: "abc4", maker: "gooduser"]
]
// you mentioned you wanted to match a specific user
String user = "baduser"
List filteredList = approvalList.findAll{ it.maker != user}​​​​​​
// wasn't sure if you wanted a single object or a list...
if (filteredList.size() == 1) {
return filteredList[0] as JSON
} else {
return filteredList as JSON
}​
Pretty simple. First parse the JSON into an object, then walk through and test.
JSONObject json = JSON.parse(text)
json.each(){ it ->
it.each(){ k,v ->
if(v=='baduser'){
// throw exception or something
}
}
}

Need help in Append JSON file using ContentMerge in Apache NIFi

I'm trying to merge a JSON file which has multiple objects. Below is my Oringinal JSON file.
{
"applicant": {
"full-name": "Tyrion Lannister",
"mobile-number" : "8435739739",
"email-id" : "tyrionlannister_casterlyrock#gmail.com"
},
"product": {
"product-category" : "Credit Card",
"product-type" : "Super Value Card - Titanium"
}
}
I will get some more JSON data as below from other source.
{
"flags": {
"duplicate-flag" : "No"
"contact-flag" : "Yes"
}
}
My task is to append the new JSON in the old JSON recods as a new object as below.
{
"applicant": {
"full-name": "Tyrion Lannister",
"mobile-number" : "8435739739",
"email-id" : "tyrionlannister_casterlyrock#gmail.com"
},
"product": {
"product-category" : "Credit Card",
"product-type" : "Super Value Card - Titanium"
},
"flags": {
"duplicate-flag" : "No"
"contact-flag" : "Yes"
}
}
Can someone help to guide, how it can be achieved in NiFi ?
I recommend accumulating your components as flowfile attributes, then forming a merged object with an ExecuteScript processor using JavaScript/ECMAScript. Sometimes there's just no substitute for JavaScript. Something like the following might work:
flowFile = session.get();
if (flowFile != null) {
var OutputStreamCallback = Java.type("org.apache.nifi.processor.io.OutputStreamCallback");
var StandardCharsets = Java.type("java.nio.charset.StandardCharsets");
// Get attributes
var applicant = JSON.parse(flowFile.getAttribute("applicant"));
var product = JSON.parse(flowFile.getAttribute("product"));
var flags = JSON.parse(flowFile.getAttribute("flags"));
// Combine
var merged = {
"applicant": applicant,
"product": product,
"flags": flags
};
// Write output content
flowFile = session.write(flowFile, new OutputStreamCallback(function(outputStream) {
outputStream.write(JSON.stringify(merged, null, "\t").getBytes(StandardCharsets.UTF_8));
}));
session.transfer(flowFile, REL_SUCCESS);
}

UWP - From Json string to Structure (Classes)

I receive a JSon string from WS. It's so long that I can't use Json2charp to parse it and receive the structurated class.
I want to parse the string with a command. How is it possible?
I don't know the classes so I can't use a command like:
Dim result = JsonConvert.DeserializeObject(Of MyClass.RootObject)(String_From_File)
Is it possible from the string to obtain the class without using json2charp site ?
For example, in vs.net if on the variable 'string_from_file' I choose 'Json Visualizer' and see all classes and data in correct mode.
How can I obtain the same in my code ?
I have installed Newtonsoft.json
If you cannot use the json to class mappers like NewtonSoft.Json. You can use the Windows.Data.Json api. It let you parse and extract the data you want from your JSON string.
JsonValue jsonValue = JsonValue.Parse("{\"Width\": 800, \"Height\": 600, \"Title\": \"View from 15th Floor\", \"IDs\": [116, 943, 234, 38793]}");
double width = jsonValue.GetObject().GetNamedNumber("Width");
double height = jsonValue.GetObject().GetNamedNumber("Height");
string title = jsonValue.GetObject().GetNamedString("Title");
JsonArray ids = jsonValue.GetObject().GetNamedArray("IDs");
You can find a sample in the Windows Universal Sample GitHub.
A complex object parsing is shown here. I've extracted the most relevant parts here. The JSON string is provided to the User constructor which is extracting what it needs and then delegating the parsing to the nested School constructor.
{
"id": "1146217767",
"phone": null,
"name": "Satya Nadella",
"education": [
{
"school": {
"id": "204165836287254",
"name": "Contoso High School"
},
"type": "High School"
},
{
"school": {
"id": "116138758396662",
"name": "Contoso University"
},
"type": "College"
}
],
"timezone": -8,
"verified": true
}
This JSON fragment is parsed with this code:
public User(string jsonString) : this()
{
JsonObject jsonObject = JsonObject.Parse(jsonString);
Id = jsonObject.GetNamedString(idKey, "");
IJsonValue phoneJsonValue = jsonObject.GetNamedValue(phoneKey);
if (phoneJsonValue.ValueType == JsonValueType.Null)
{
Phone = null;
}
else
{
Phone = phoneJsonValue.GetString();
}
Name = jsonObject.GetNamedString(nameKey, "");
Timezone = jsonObject.GetNamedNumber(timezoneKey, 0);
Verified = jsonObject.GetNamedBoolean(verifiedKey, false);
foreach (IJsonValue jsonValue in jsonObject.GetNamedArray(educationKey, new JsonArray()))
{
if (jsonValue.ValueType == JsonValueType.Object)
{
Education.Add(new School(jsonValue.GetObject()));
}
}
}
public School(JsonObject jsonObject)
{
JsonObject schoolObject = jsonObject.GetNamedObject(schoolKey, null);
if (schoolObject != null)
{
Id = schoolObject.GetNamedString(idKey, "");
Name = schoolObject.GetNamedString(nameKey, "");
}
Type = jsonObject.GetNamedString(typeKey);
}
If you cannot use the automatic mapping from NewtonSoft.Json, you have no other way than doing it yourself.
Is not so simple.
The Json i received is very complicated and have many class
So i can't use
double width = jsonValue.GetObject().GetNamedNumber("Width");
Inside class i have more ...

JSON.net parsing of dynamic JSON

I have JSON that looks like this:
{
"status": {
"code": 0,
"message": "OK"
},
"data": {
"_idtype": "cusip",
"_id": "00768Y883",
"api": {
"_name": "PortfolioBreakdownsRaw",
"PortfolioDate": "2015-10-12",
"GlobalBondSuperSectorLongSalePositionBreakdown": [
{
"Name": "Municipal",
"Value": "0.57842"
},
{
"Name": "Corporate",
"Value": "1.79649"
},
{
"Name": "Securitized",
"Value": "5.29493"
},
{
"Name": "Cash & Equivalents",
"Value": "166.20776"
}
],
"GlobalBondSuperSectorShortSalePositionBreakdown": [
{
"Name": "Government",
"Value": "0.90557"
}
]
}
}
}
I am able to get the api portion of the response easily:
var jObject = JObject.Parse(json);
var api = jObject["data"]["api"];
From here, I don't what if any arrays will be included in the response. The ultimate goal will be to create a parser that will be able to get the array names (GlobalBondSuperSectorShortSalePositionBreakdown) and as many rows of key-value pairs that it may contain, without first knowing the names such as (GlobalBondSuperSectorShortSalePositionBreakdown) beforehand.
I can't seem to find a good way to loop through the object, determine there are arrays at the api level and then iterate through those to get the values.
Any help would be appreciated.
Here's an example. In this code, the api variable holds a JObject, so we can iterate over its properties. From there, we look at the Type of each property value to see if it is an array or not. If it is, then we can iterate over that array to get the JObjects within it, and extract the Name and Value values that we expect to find there. Does this help?
var jObject = JObject.Parse(json);
var api = jObject["data"]["api"];
foreach (JProperty prop in api.Children<JProperty>())
{
JToken value = prop.Value;
if (value.Type == JTokenType.Array)
{
Console.WriteLine(prop.Name + ": ");
foreach (JObject jo in value.Children<JObject>())
{
Console.WriteLine(" " + jo["Name"] + ": " + jo["Value"]);
}
}
else
{
Console.WriteLine(prop.Name + ": " + value);
}
}
Output:
_name: PortfolioBreakdownsRaw
PortfolioDate: 2015-10-12
GlobalBondSuperSectorLongSalePositionBreakdown:
Municipal: 0.57842
Corporate: 1.79649
Securitized: 5.29493
Cash & Equivalents: 166.20776
GlobalBondSuperSectorShortSalePositionBreakdown:
Government: 0.90557
Fiddle: https://dotnetfiddle.net/XyoXQy
With Linq you can play pretty nice with Json.net:
Here is an easily readable version of the chunk of code that will create two dictionaries out of the JArray properties under the api element:
var api = jObject["data"]["api"];
var arrays = api.Cast<JProperty>().Where(o => o.Value.Type == JTokenType.Array).Select(token => token.Value).ToArray();
var dictionaries = new List<Dictionary<string, string>>();
foreach (var array in arrays)
{
var dictionary = array.ToDictionary(token => token["Name"].Value<string>(), token => token["Value"].Value<string>());
dictionaries.Add(dictionary);
}
alternative:
The same thing, but a shorter, more compact version :
var api = jObject["data"]["api"];
var dictionaries = api
.Cast<JProperty>()
.Where(o => o.Value.Type == JTokenType.Array)
.Select(token => token.Value)
.Select(array => array.ToDictionary(token => token["Name"].Value<string>(), token => token["Value"].Value<string>()));

Actionscript3 parsing json with an object

I have a flash app where in a function I have to parse a json passed like an object by some external API that I can't change.
my json look like this:
{
"prodotti": [
{
"titolo": "test",
"marca": "",
"modello": "",
"cilindrata": "",
"potenza": "",
"alimentazione": "",
"images": {
"img": [
{
"thumb": "admin/uploads/img_usato/small/qekabw95L5WH1ALf6.jpg",
"big": "admin/uploads/img_usato/big/qekabw95L5WH1ALf6.jpg"
},
{
"thumb": "admin/uploads/img_usato/small/default.jpg",
"big": "admin/uploads/img_usato/big/default.jpg"
}
]
}
},
{
"titolo": "Motore Volvo TAMD 74 C",
"marca": "VOLVO PENTA",
"modello": "TAMD 74 C",
"cilindrata": "7.283 cm3",
"potenza": "331 kW a 2600 rpm",
"alimentazione": "Gasolio",
"images": {
"img": [
{
"thumb": "admin/uploads/img_usato/small/PmQwN4t4yp7P1YCWa.jpg",
"big": "admin/uploads/img_usato/big/PmQwN4t4yp7P1YCWa.jpg"
},
{
"thumb": "admin/uploads/img_usato/small/BWkjTGcy3pDM2LKRs.jpg",
"big": "admin/uploads/img_usato/big/BWkjTGcy3pDM2LKRs.jpg"
}
]
}
}
]
}
I want to parse the images inside the object.
The API send me an object not astring or json and I have this function now:
function changeData (prodotto:Object) {
img_container.graphics.clear ();
//here I want to enter and take thumb and big of images!!!
for (var index in prodotto.images.img) {
//trace('index: ' + index);
//trace("thumb: " + index.thumb + ' big: ' + index.big);
}
descrizione.htmlText = prodotto.testo_html;
titolo.text = prodotto.titolo;
alimentazione.text = prodotto.alimentazione;
potenza.text = prodotto.potenza;
cilindrata.text = prodotto.cilindrata;
modello.text = prodotto.modello;
marca.text = prodotto.marca;
}
The function works fine but not for the for loop where I try to take the bug and thumb of my json how can I retrieve this information in this object?
Thanks
I think there is something wrong with how you are setting up the call back but since you didn't show code for the api we can't fix that, plus you stated you have no control over it.
No matter what the issue is it just does not seem correct.
I put together a function that will get all the thumbs and bigs.
You did not state otherwise.
function changeData (prodotto:Object) {
for each(var item in prodotto.prodotti){
trace('')
//trace(prodotto.testo_html);
trace(item.titolo);
trace(item.alimentazione);
trace(item.potenza);
trace(item.cilindrata);
trace(item.modello);
trace(item.marca);
for each( var imgs in item.images.img) {
trace('thumb',imgs.thumb)
trace('big',imgs.big)
}
}
}
I think you need to use a JSON parser. Use the one from this link: https://github.com/mikechambers/as3corelib
1: Add the com folder to your project directory or add it to your default class path.
2: Adapt this code to your liking. I am not sure how you're getting a literal object from the API. It really should just be a string unless you're using some sort of AMF. Regardless...
import com.adobe.serialization.json.*;
var data:String = '{"prodotti":[{"titolo":"test","marca":"","modello":"","cilindrata":"","potenza":"","alimentazione":"","images":{"img":[{"thumb":"admin/uploads/img_usato/small/qekabw95L5WH1ALf6.jpg","big":"admin/uploads/img_usato/big/qekabw95L5WH1ALf6.jpg"},{"thumb":"admin/uploads/img_usato/small/default.jpg","big":"admin/uploads/img_usato/big/default.jpg"}]}},{"titolo":"Motore Volvo TAMD 74 C","marca":"VOLVO PENTA","modello":"TAMD 74 C","cilindrata":"7.283 cm3","potenza":"331 kW a 2600 rpm","alimentazione":"Gasolio","images":{"img":[{"thumb":"admin/uploads/img_usato/small/PmQwN4t4yp7P1YCWa.jpg","big":"admin/uploads/img_usato/big/PmQwN4t4yp7P1YCWa.jpg"},{"thumb":"admin/uploads/img_usato/small/BWkjTGcy3pDM2LKRs.jpg","big":"admin/uploads/img_usato/big/BWkjTGcy3pDM2LKRs.jpg"}]}}]}';
function changeData(data)
{
img_container.graphics.clear();
var obj = JSON.decode(data);
for (var i:int = 0; i < obj.prodotti.length; i++)
{
for (var k in obj.prodotti[i].images.img)
{
trace("Thumb:",obj.prodotti[i].images.img[k].thumb);
trace("Big:",obj.prodotti[i].images.img[k].big);
}
descrizione.htmlText = obj.prodotti[i].testo_html;
titolo.text = obj.prodotti[i].titolo;
alimentazione.text = obj.prodotti[i].alimentazione;
potenza.text = obj.prodotti[i].potenza;
cilindrata.text = obj.prodotti[i].cilindrata;
modello.text = obj.prodotti[i].modello;
marca.text = obj.prodotti[i].marca;
}
}
changeData(data);