How do I manage a JSON response with ASOC Foundation

A URL query for apple in an api named emoji-api at https://emoji-api.com with

returned the following NSArray.

(Unfortunately, the emojis cannot be viewed in this posting format and show only as “???”)

From that array, I would like to create a choose from list command concatenating two values, such as unicodeName and character.

To solve this problem, I can think of three options to manage the json array.
a. Filter via predicate
b. Parse
c. Data detect

Even so, I am unsure as to methods of writing ASOC Foundation code to assemble a list from the json response.

  1. If any of those three possible Foundation codes would succeed in managing the json response, how could I write them?
  2. If other better Foundation options exist, what might they be?

I think, you need something like this


use framework "Foundation"
use scripting additions
property myFreePrivateKey : "43b425795a72994b3b4cd305488a4b2d24008dae"

set theUrl to "https://emoji-api.com/emojis?search=apple&access_key=" & myFreePrivateKey

set theNSURL to current application's NSURL's URLWithString:theUrl
set jsonData to current application's NSData's dataWithContentsOfURL:theNSURL
set theNSArray to (current application's NSJSONSerialization's JSONObjectWithData:jsonData options:0 |error|:(missing value))

set unicodeNamesAndCharacters to {}
repeat with anItem in (theNSArray as list)
	tell anItem
		set end of unicodeNamesAndCharacters to (its unicodeName & "  " & its |character|)
	end tell
end repeat

return unicodeNamesAndCharacters

Implementing choose from list approach:


use framework "Foundation"
use scripting additions
property myFreePrivateKey : "43b425795a72994b3b4cd305488a4b2d24008dae"

set theUrl to "https://" & "emoji-api.com/emojis?search=apple&access_key=" & myFreePrivateKey

set theNSURL to current application's NSURL's URLWithString:theUrl
set jsonData to current application's NSData's dataWithContentsOfURL:theNSURL
set theNSArray to (current application's NSJSONSerialization's JSONObjectWithData:jsonData options:0 |error|:(missing value))

set unicodeNames to {}
set theCharacters to {}
repeat with anItem in (theNSArray as list)
	tell anItem
		set end of unicodeNames to its unicodeName
		set end of theCharacters to its |character|
	end tell
end repeat

set theChoice to choose from list unicodeNames
if theChoice is false then return false
set theChoice to item 1 of theChoice

repeat with i from 1 to count unicodeNames
	if theChoice is (item i of unicodeNames) then
		return item i of theCharacters
	end if
end repeat

Thanks for your ideas, KniazidisR.

In an attempt to retrieve a larger set of data, I tried requesting an API response from this emoji API, using a search value of “hand”,

set theUrl to "https://" & "emoji-api.com/emojis?search=hand&access_key=" & myFreePrivateKey

I followed that one line of code with subsequent lines from your code:

set theNSURL to current application's NSURL's URLWithString:theUrl
set jsonData to current application's NSData's dataWithContentsOfURL:theNSURL
set theNSArray to (current application's NSJSONSerialization's JSONObjectWithData:jsonData options:0 |error|:(missing value))

Although the API URL request, connection and data retrieval required in the neighborhood of 1 second, the subsequent repeat loop to aggregate the data required up to 10 seconds.


set JSONValueList to {}
repeat with anItem in (theNSArray as list)
	tell anItem
		set end of JSONValueList to its |character| & its unicodeName
	end tell
end repeat

In an attempt to find a faster solution, I was wondering:

  1. What Foundation ASOC might avoid the loop and aggregate only the JSON values corresponding to its key words character and unicodeName?
  2. Would that ASOC yield the JSON array’s data more quickly?

Hi, again.

The repeat loop can’t be avoided, but I think, it should became faster with implicit script object declaration. Test the following and tell us the result:


set JSONValueList to my {}
repeat with anItem in (theNSArray as list)
	tell anItem
		set end of my JSONValueList to its |character| & its unicodeName
	end tell
end repeat

Thanks for your response, KniazidisR, but it appears to me that the script you wanted me to try was an exact copy of the script that I previously posted, that from my experience, required an excessive amount of time, that is to say over 10 seconds, to run. Perhaps, you meant to post a varying script, for me to try. If so, I would be interested in your ideas.

I tested my last sentence with my - specifier myself. I can now say that this did not add speed greatly. Although, for me everything is calculated for 527 elements not in 11 seconds like yours, but in 1 - 1.5 seconds. I tested this:


use framework "Foundation"
use scripting additions
property myFreePrivateKey : "43b425795a72994b3b4cd305488a4b2d24008dae"

set theUrl to "https://" & "emoji-api.com/emojis?search=hand&access_key=" & myFreePrivateKey

set theNSURL to current application's NSURL's URLWithString:theUrl
set jsonData to current application's NSData's dataWithContentsOfURL:theNSURL
set theNSArray to (current application's NSJSONSerialization's JSONObjectWithData:jsonData options:0 |error|:(missing value))

set JSONValueList to my {}
repeat with anItem in (get theNSArray as list) -- added "get" as well
	tell anItem
		set end of my JSONValueList to its |character| & its unicodeName
	end tell
end repeat

return JSONValueList

Thank you, KniazidisR. After testing my sample against yours, I realized that much of the slowness in the script arose from running in Debugging mode in Script Debugger’s application. After I exited that mode, the script ran much faster, returning execution times similar to yours. I appreciate your help.
In my attempt to avoid an applescript loop, which I thought might be requiring more time for execution, I substituted the Applescript code

set JSONValueList to my {}
repeat with anItem in (get theNSArray as list) -- added "get" as well
   tell anItem
       set end of my JSONValueList to its |character| & its unicodeName
   end tell
end repeat
return JSONValueList

with an ASOC code

set JSONValueList to ((current application's NSArray's arrayWithArray:jsonArray)'s valueForKey:"character") as list

to reduce the running time further, in the range of a few tenths of a second to a full second.

With Array’s valueForKey, does a method exist to concatenate two values, such as the values for character and unicodeName?

Hi.Again. :smiley:

As I know, there is no AsObjC method for elementwise concatenation of arrays. But your question gave me an idea. It is possible to get everything in the form of a record. I think it will even be more practical, and faster:


use framework "Foundation"
use scripting additions
property myFreePrivateKey : "43b425795a72994b3b4cd305488a4b2d24008dae"

set theUrl to "https://" & "emoji-api.com/emojis?search=hand&access_key=" & myFreePrivateKey

set theNSURL to current application's NSURL's URLWithString:theUrl
set jsonData to current application's NSData's dataWithContentsOfURL:theNSURL
set jsonArray to ¬
	(current application's NSJSONSerialization's JSONObjectWithData:jsonData options:0 |error|:(missing value))
set {theKeys, theValues} to ¬
	{jsonArray's valueForKey:"unicodeName", jsonArray's valueForKey:"character"}

(current application's NSDictionary's dictionaryWithObjects:theValues forKeys:theKeys) as record

Thanks, KniazidisR, for your novel perspective. Your NSDictionary’s dictionaryWithObjects approach

set {theKeys, theValues} to  {jsonArray's valueForKey:"unicodeName", jsonArray's valueForKey:"character"}
set JsonRecord to (current application's NSDictionary's dictionaryWithObjects:theLabels forKeys:theKeys) as record

appears to assemble correlating values of the same object, without extending the script’s duration of execution.