I have an iOS application which parses a JSON feed provided by Google Plus. This JSON feed contains links, titles, etc for posts on a Google Plus profile.
The JSON file in certain parts has an array called "attachments" and that array has the image URL which I am parsing.
The problem is that that array is not always present, so sometime its available with the image URL and sometime its not even there.
As a result of this, when I parse for the image URL my iOS application crashes because the array it is looking for is not always present.
So how can I test to see if the array is present before deciding to parse for the image URL. I tried to make a simple if-statement, but it doesn't seem to work. Here it is:
if ([[[episodes objectAtIndex:index] valueForKey:#"object"] valueForKey:#"attachments"] == [NSNull null]) {
NSLog("No image to parse.");
}
else {
// parse image link
}
Here is the JSON file:
{
"kind": "plus#activity",
"etag": "\"9Q4kEgczRt3gWehMocqSxXqUhYo/uQcxIDsySGhlI5hMFHcxjuBhM9k\"",
"title": "",
"published": "2013-02-24T22:30:25.159Z",
"updated": "2013-02-24T22:30:25.159Z",
"id": "z13jgdihsvnytdttc23hxdz5ypfsjnzsb",
"url": "https://plus.google.com/102757352146004417544/posts/7psQLdwS2F7",
"actor": {
"id": "102757352146004417544",
"displayName": "Daniel Sadjadian",
"url": "https://plus.google.com/102757352146004417544",
"image": {
"url": "https://lh4.googleusercontent.com/-EF0LibpIsEY/AAAAAAAAAAI/AAAAAAAAALQ/2nt32bqYBtM/photo.jpg?sz=50"
}
},
"verb": "post",
"object": {
"objectType": "note",
"content": "",
"url": "https://plus.google.com/102757352146004417544/posts/7psQLdwS2F7",
"replies": {
"totalItems": 0,
"selfLink": "https://www.googleapis.com/plus/v1/activities/z13jgdihsvnytdttc23hxdz5ypfsjnzsb/comments"
},
"plusoners": {
"totalItems": 0,
"selfLink": "https://www.googleapis.com/plus/v1/activities/z13jgdihsvnytdttc23hxdz5ypfsjnzsb/people/plusoners"
},
"resharers": {
"totalItems": 0,
"selfLink": "https://www.googleapis.com/plus/v1/activities/z13jgdihsvnytdttc23hxdz5ypfsjnzsb/people/resharers"
},
"attachments": [
{
"objectType": "video",
"displayName": "SGU - The Game Has Changed!",
"content": "Send this video to your friends to spread the word about the upcoming SyFy marathon. This very well may be our last chance to save the show. If you're in the...",
"url": "http://www.youtube.com/watch?v=WtHusm7Yzd4",
"image": {
"url": "https://lh3.googleusercontent.com/proxy/z9shhK2d39jM2P-AOLMkqP2KMG2DjipCWlcPeVPaRvHkfj-nmxkxqZfntAVMoV88ZOuroRHIvG4qs-K0SaMjQw=w506-h284-n",
"type": "image/jpeg",
"height": 284,
"width": 506
},
"embed": {
"url": "http://www.youtube.com/v/WtHusm7Yzd4?version=3&autohide=1",
"type": "application/x-shockwave-flash"
}
}
]
},
"provider": {
"title": "Google+"
},
"access": {
"kind": "plus#acl",
"description": "Public",
"items": [
{
"type": "public"
}
]
}
},
Thanks for your time, Dan.
UPDATE:
Just assign that to array and check the array is nil.
NSMutableArray *attachments = [[[episodes objectAtIndex:index] valueForKey:#"object"] valueForKey:#"attachments"];
if (!attachments) {
NSLog("No image to parse.");
}
This will work.
I don't see the problem (please post your error details) but when dealing with JSON, I like to use a category IfNullThenNil. Your code would look like:
if ( [ [ episodes[index] valueForKeyPath:#"object.attachments" ] ifNullThenNil ]
{
// parse image link
}
else
{
NSLog(#"No image to parse.\n");
}
Here's the category on NSObject/NSNull
#implementation NSObject (IfNullThenNil)
-(id)ifNullThenNil
{
return self ;
}
#end
#implementation NSNull (IfNullThenNil)
-(id)ifNullThenNil
{
return nil ;
}
#end
Related
I fetched two emails from Gmail via their APIs, one contains an inline picture, the other contains an picture attachment. See their HTTP response below.
By comparing these two sections, I am not able to tell which picture is attached and which is inline. "Content-Disposition" shows that both are attachments, though one of them is actually an inline photo.
Is there a way to identify inline pictures with the response from Gmail API?
// inline
{
"partId": "2",
"mimeType": "image/heic",
"filename": "image_50410497.JPG",
"headers": [
{
"name": "Content-Type",
"value": "image/heic; name=\"image_50410497.JPG\""
},
{
"name": "Content-Disposition",
"value": "attachment; filename=\"image_50410497.JPG\""
},
{
"name": "Content-Transfer-Encoding",
"value": "base64"
},
{
"name": "X-Attachment-Id",
"value": "18334b929992fd46a211"
},
{
"name": "Content-ID",
"value": "\u003c18334b929992fd46a211\u003e"
}
],
"body": {
"attachmentId": "ANGjdJ8FshN6fd_2OoZEttwPYHk_8q1mVOJevilskBM-6yOZZ6aMMSMblU3Vo5pw-V1_SeDzxkVx0zOg5R-9fGkaSGvGzd6Wi9yVBe4dAn03HDCghyUWFC2jyodeWYmttzzaXyCNRUVPdVxmO7l8yTaeEsQ4Ep1Ze7Nc3bnLNozWHeKZQHQLqGyfLKDdEI1GKjT8X6OuyEY6EWMo8djE30c-BvYjuY95vmomjkjzfoIqTFfpUlMMktNUfvC1SZMHL0arymXmTTM6uVg5N0U2TngVfbKNx0x8hI0bhccB-AiIhwrSqCxM_CZkyXrGRcY",
"size": 2607632
}
},
// attached
{
"partId": "1",
"mimeType": "image/jpeg",
"filename": "unnamed.jpeg",
"headers": [
{
"name": "Content-Type",
"value": "image/jpeg; name=\"unnamed.jpeg\""
},
{
"name": "Content-Disposition",
"value": "attachment; filename=\"unnamed.jpeg\""
},
{
"name": "Content-Transfer-Encoding",
"value": "base64"
},
{
"name": "Content-ID",
"value": "\u003cf_l83jtl4x0\u003e"
},
{
"name": "X-Attachment-Id",
"value": "f_l83jtl4x0"
}
],
"body": {
"attachmentId": "ANGjdJ_6KFGMzvKW6XFwD4BaSjCDSQGWPEMpL97DE1Lx31cKi2cSzSTOMDIdTEV8wyvnLiB8iqg5_1CVlDOOofl4NiEll2IwrxDuE-IdDXP9PmryOXbMp0pFgIQ961UQWQk8yhObqPcx8xWnqQaPWI3pwirH6hhoe3JtswoLXQ1NDs7FjJZ2iivLZHoTvMlh-i4VQIK6JVaEdIcQBejI6WruTi7DuC_ZpRwewfReZ2JsPKtncVCFwOkb0Ov1vElLS7Y1BTATiRzurXQw1A4lYOn5-XDKqXk90p_HxEQO5zEsvdz2MigVSa803-mIvK8RFTyOOuA4iVWEzad0I3mEFVE6bxTfFQ_YnAYm1FLKImnMEkJf5MuyZofZleyu8fjTGGqzvWmjikDGLvAzdM2O",
"size": 1553427
}
}
UPDATE:
Max mentioned 'Content-ID', I can confirm it works for some emails I have, here is an example:
// header of the attachment part
{
"name": "Content-ID",
"value": "\u003cii_l83jb7dh0\u003e"
}
// decoded HTML body
<img src="cid:ii_l83jb7dh0" alt="20190906-2P2A3622.jpeg" width="361" height="542"><br>
Sometimes the only thing that distinguishes them is whether the Content-ID is referenced in the HTML body of the message. More precisely, by any reasonable definition, that image is an attachment, but it may also be referenced as a cid: url in an <img> tag in an HTML mime part. The header information alone cannot tell you that.
I am trying to fetch Pages from Sharepoint sites using graph API.
But when we make GET request with
https://graph.microsoft.com/beta/sites/{site-id}/pages/{page-id}
the response consists of webParts which only have type and data.
Inside data we have an id(which same as type) and an instanceId that is unique for every webPart.
Sample webPart:
{
"type": "d1d91016-032f-456d-98a4-721247c305e8",
"data": {
"id": "d1d91016-032f-456d-98a4-721247c305e8",
"instanceId": "c54a74ef-86c1-44aa-9ba4-802e6841e3a7"
}
My goal is to fetch webPages with complete details and then backup them to a local drive in any format.
The documentation of graph API shows that the responce would consist of complete details for the webPart, but it is not so.
Documentation link: https://learn.microsoft.com/en-us/graph/api/sitepage-get?view=graph-rest-beta&tabs=http
Sample request URL:
https://graph.microsoft.com/beta/sites/m365x214355.sharepoint.com,c1e5444e-12d8-43d3-96b1-f2f66559ef58,b181bdf0-9680-4988-81f7-a24aee4afd6a/pages
Webpart repsonse:
"webParts": [
{
"type": "rte",
"data": {
"innerHTML": "<p>Take a look at the team behind delivering amazing fashion events for Contoso.</p><p>Find out how the team uses the latest technology to plan amazing fashion shows and gather customer feedback for future events.</p><p>Meet the people behind Contoso's events, learn how to plan your own event, and find the necessary resources to run highly successful fashion shows, premiers, and extravaganzas!</p>"
}
},
{
"type": "d1d91016-032f-456d-98a4-721247c305e8",
"data": {
"id": "d1d91016-032f-456d-98a4-721247c305e8",
"instanceId": "c54a74ef-86c1-44aa-9ba4-802e6841e3a7"
}
},
{
"type": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"data": {
"id": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"instanceId": "75ccfeba-ad6c-416d-a859-4a6b114e156e"
}
},
{
"type": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"data": {
"id": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"instanceId": "f04e02fb-45e6-4e74-9f46-0c8d90e7fb8d"
}
},
{
"type": "275c0095-a77e-4f6d-a2a0-6a7626911518",
"data": {
"id": "275c0095-a77e-4f6d-a2a0-6a7626911518",
"instanceId": "c1a222b0-624e-4e30-b544-d2a67e8e1112"
}
}
Expected Response format:
"webParts": [
{
"type": "rte",
"data": {
"innerHTML": "<p>Here are the team's upcoming events:</p>"
}
},
{
"type": "d1d91016-032f-456d-98a4-721247c305e8",
"data": {
"title": "Events",
"description": "Display upcoming events",
"serverProcessedContent": {
"htmlStrings": {},
"searchablePlainTexts": {
"title": ""
},
"imageSources": {},
"links": {
"baseUrl": "https://www.contoso.com/sites/Engineering"
},
"componentDependencies": {
"layoutComponentId": "8ac0c53c-e8d0-4e3e-87d0-7449eb0d4027"
}
},
"dataVersion": "1.0",
"properties": {
"selectedListId": "032e08ab-89b0-4d8f-bc10-73094233615c",
"selectedCategory": "",
"dateRangeOption": 0,
"startDate": "",
"endDate": "",
"isOnSeeAllPage": false,
"layoutId": "FilmStrip",
"dataProviderId": "Event",
"webId": "0764c419-1ecc-4126-ba32-0c25ae0fffe8",
"siteId": "6b4ffc7a-cfc2-4a76-903a-1cc3686dee23"
}
}
}
]
I want webParts in the format as per documentation.
If the instanceId is unique then there might be some reference table to match these instanceIds and fetch the detailed webParts structure.
I have a problem with sending a JSON response from UITableView into another UITableView.
I want to send the Products array like in the code below into another UITableViewController based on the selected row on the TableView, but when I log the value in didSelectRowAt it returns nil.
So here's the JSON return.
{
"error_description": [],
"results": [
{
"id": 2,
"name": "Ernser, Kilback and Kreiger LLC",
"address": "48788 Adaline Ville 7634 Bertram Shoal",
"contact_person": "Coralie Schaden",
"mobile_number": "(238) 076-0562",
"image": {
"url": null,
"thumb": {
"url": null
},
"medium": {
"url": null
},
"small": {
"url": null
},
"icon": {
"url": null
}
},
"registered_at": "2017-01-10T04:16:52.621Z",
"products": [
{
"id": 21,
"name": "Fantastic Rubber Car",
"image": {
"url": null,
"thumb": {
"url": null
},
"medium": {
"url": null
},
"small": {
"url": null
},
"icon": {
"url": null
}
},
"points": 0,
"merchant_id": 2,
"created_at": "2017-01-10T04:16:52.630Z",
"updated_at": "2017-01-10T04:16:52.636Z"
},
{
"id": 22,
"name": "Mediocre Plastic Shirt",
"image": {
"url": null,
"thumb": {
"url": null
},
"medium": {
"url": null
},
"small": {
"url": null
},
"icon": {
"url": null
}
},
"points": 15,
"merchant_id": 2,
"created_at": "2017-01-10T04:16:52.819Z",
"updated_at": "2017-01-10T04:16:52.827Z"
},
]
}
This is a part of my code for getting the response.
I used the Alamofire
var merchantModel: Merchant!
var merchantArr = [Merchant]()
var productArr = [Product]()
var productModel : Product?
.....
case .success:
let json = JSON(data: response.data!)
for result in json["results"].arrayValue{
guard let merchantID = result["id"].number, let merchantName = result["name"].string, let merchantAddress = result["address"].string, let contactPerson = result["contact_person"].string, let mobilenumber = result["mobile_number"].string else{
return
}
self.merchantModel = Merchant(merchantID: merchantID, merchantName: merchantName, merchantAddress: merchantAddress, contactPerson: contactPerson, mobileNumber: mobilenumber, merchantImage: contactPerson)
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(self.merchantModel!, toFile: Merchant.ArchiveURL.path)
if !isSuccessfulSave {
print("Failed to save sender...")
}
for prodArr in result["products"].arrayValue{
print("prodArr:\(prodArr)")
guard let prodID = prodArr["id"].number, let prodName = prodArr["name"].string,
let points = prodArr["points"].number else{
return
}
self.productModel = Product(productID: prodID, productName: prodName, productPoints: points)
}
self.merchantArr.append(self.merchantModel!)
self.productArr.append(self.productModel!)
self.merchantModel.loadMerchant()
self.tableView.reloadData()
}
Swift is not javascript, and JSON is not the simplest way to handle the data in this language.
You'd probably prefer to transform your JSON data into Foundation objects, manipulate them, create UITableView with them... And when you'll need to have the JSON format again, you transform those Foundation objects back to JSON.
There are a lot of ways to achieve that, and some amazing third-party libraries to do it very easily. However for a start I encourage you to have a look at Apple's resources :
NSJSONSerialization
Working with JSON in Swift
I have a JSON array with multiple object and I don't know how do I grab the "url" tag as an NSArray or a NSDictionary and show that image url in Tableview. I can't change the JSON data format.How should I do this?
Here is what the JSON response looks like:
{
"meta": {
"total_count": 10
},
"pages": [
{
"id": 7,
"meta": {
"type": "dashboard.NewsEvents",
"detail_url": "http://suno.to/api/v1/pages/7/"
},
"title": "NoEvent",
"created_at": "2016-03-06T10:42:19.646000Z",
"cover_url": [
[
{
"url": "/media/images/Maha_Shivratri2.original.jpg",
"title": "Maha Shivratri2.jpg"
},
{
"url": "/media/images/Maha_Shivratri1.original.jpg",
"title": "Maha Shivratri1.jpg"
}
],
[
{
"url": "/media/images/Celebrations.original.jpg",
"title": "Celebrations.jpg"
},
{
"url": "/media/images/Crew.original.jpg",
"title": "Crew.jpg"
},
{
"url": "/media/images/World_record.original.jpg",
"title": "World record.jpg"
},
{
"url": "/media/images/AI_pilots.original.jpg",
"title": "AI pilots.jpg"
}
],
[
{
"url": "/media/images/CbVv-VbWEAAmwv_.original.jpg",
"title": "DAL SWARAJ YATRA"
},
{
"url": "/media/images/CbVv_-TWwAE7RjM.original.jpg",
"title": "DAL SWARAJ YATRA"
},
{
"url": "/media/images/CbVv_SmXIAALQP8.original.jpg",
"title": "DAL SWARAJ YATRA"
},
{
"url": "/media/images/CahEc--UkAArc_z.original.jpg",
"title": "DAL SWARAJ YATRA"
}
]
]
},
{
"id": 2530,
"meta": {
"type": "dashboard.NewsEvents",
"detail_url": "http://suno.to/api/v1/pages/2530/"
},
"title": "World Culture Festival",
"created_at": "2016-03-12T06:59:21.023000Z",
"cover_url": [
[
{
"url": "/media/images/Security.original.jpg",
"title": "Security check"
}
],
[
{
"url": "/media/images/Elephant_statues.original.jpg",
"title": "Elephant"
}
],
[
{
"url": "/media/images/6.original.jpg",
"title": "Stage"
},
{
"url": "/media/images/4.original.jpg",
"title": "Stage"
}
]
]
},
{
"id": 2675,
"meta": {
"type": "dashboard.NewsEvents",
"detail_url": "http://suno.to/api/v1/pages/2675/"
},
"title": "Holi in Barsana",
"created_at": "2016-03-17T12:35:09.308000Z",
"cover_url": [
[
{
"url": "/media/images/Brajwasi_playing_holi_.original.jpg",
"title": "Holi in Barsana"
},
{
"url": "/media/images/dancing_.original.jpg",
"title": "Holi in Barsana"
},
{
"url": "/media/images/holi.._.original.jpg",
"title": "Holi in Barsana"
},
{
"url": "/media/images/holi..._.original.jpg",
"title": "Holi in Barsana"
}
],
[
{
"url": "/media/images/Lathmar_holi_19_n54f7LJ.original.jpg",
"title": "Lathmar Holi in Barsana"
}
],
[
{
"url": "/media/images/Lathmar_holi_17.original.jpg",
"title": "Lathmar Holi in Barsana"
},
{
"url": "/media/images/Lathmar_holi_20.original.jpg",
"title": "Lathmar Holi in Barsana"
}
]
]
},
I'm using this code to get the "url" array. Plz correct me ?
NSArray *imageUrlArray = [[self.jsonData objectAtIndex:indexPath.row]objectForKey:#"cover_url"];
NSLog(#"IMAGE URL ARRAY:%#",imageUrlArray);
NSString *imageUrl = [imageUrlArray valueForKey:#"url"];
NSLog(#"IMAGE URL:%#",imageUrl);
To view the JSON structure - http://jsonviewer.stack.hu/
NSMutableArray* imageurlArray = [NSMutableArray new];
NSArray* jsonArray = jsonData[#"pages"];
for (int i = 0; i<[jsonArray count]; i++) {
NSArray* coverUrlArray = jsonArray[i][#"cover_url"];
for (int t = 0; t< [coverUrlArray count]; t++) {
NSArray* UrlArray = coverUrlArray[t];
for (int x = 0; x<[UrlArray count]; x++) {
[imageurlArray addObject:UrlArray[x][#"url"]];
}
}
}
NSLog(#"imageurlArray: %#", imageurlArray);
//imageurlArray contains all url
//In cell for row at indexpath --> use imageurlArray[indexPath.row];
You have array wrappped by another array.
So, use this direction:
NSDictionary *json=//..initialized
NSArray *pages = [json valueForKey#"pages"];
NSDictionary *page = [pages objectAtIndex:0];
NSArray *ar1 = [page valueForKey#"cover_url"];
NSArray *ar2 = [ar1 objectAtIndex:0];
NSDictionary *elem = [ar2 objectAtIndex:0];
NSString *value = [elem valueForKey#"url"];
I would suggest using Mantel or JSONModel libraries for parsing objects and having decent DTOs.
When you deal with something like this, i suggest putting the complete json in http://jsonviewer.stack.hu/ so you can see the correct structure without getting confused.
Then it's just a matter of digging. When you see { }, you add a dictionary, when you see [ ], you add an array, until you reach your url object :)
I'm not writing the code because it is pretty trivial, just a mix of objectForKeys for dictionaries and objectAtIndex for arrays.
The last layers are just objects, so they're handled like any other object.
If you're confused about json, I suggest you try giving your json-parser a simple json (you hard core it yourself just above, its really just for testing).
Small advice :
Give it a simple array of 1 object, then 2, then put the array in a dict, then two, etc. and you keep making the json more complex until you really understand how it works. Then you'll eventually have a fake json just like your real one, and you can remove the fake and use the real one :)
Other advice :
There are many json parsing libraries that let you create the object model, where you can create (for example) a Page object that has an ID, a title, a cover URl, etc. that matches the JSON structure, and then you just tell the parser " make that JSON a Page!" and voilà, you have a Page. I don't know any of those json libraries in ios, but people will surely link it here, so try it out ! They're super easy to use and make json parsing really straightforward. And also, you don't have to map everything manually like you're doing ;)
Okay, here is the task:
I've already read the whole documentation and I noticed that I can "upgrade" a data type like string to a multi field - in a test scenario it already worked.
My documents structure is currently:
{
"name": "test",
"words": [
{
"words": "hello world",
"verts": [
1,
2,
3
]
}
]
}
These documents were created using the default mappings - so no mapping has been set explicitly.
I am issuing a XDELETE command with data like:
{
"article": {
"properties": {
"words": {
"type": "multi_field",
"fields": {
"words": {
"type": "string",
"index": "analyzed"
},
"untouched": {
"type": "string",
"index": "not_analyzed"
}
}
}
}
}
}
But I receive this error here:
{"error":"MergeMappingException[Merge failed with failures {[Can't
merge a non multi_field / non simple mapping [words] with a
multi_field mapping [words]]}]","status":400}
Can someone explain to me, why this happens? When I issue this mapping to a clean index, it works and the not_analyzed filter is being applied.
Thanks :)
Jan
Because the "words" field in your document has properties of its own ("words" and "verts"), you can't "upgrade" it to a multi_field. However, if you had a mapping like
{
"article": {
"properties": {
"words": {
"properties": {
"words": {
"type": "multi_field",
"fields": {
"words": {
"type": "string",
"index": "analyzed"
},
"untouched": {
"type": "string",
"index": "not_analyzed"
}
}
}
}
}
}
}
}
then everything should work out.