Getting an array of dictionaries into an AppleScript

I have created a command-line Utility in Objective-C that massages a bunch of records in an SQLite database and generates an NSArray of NSDictionaries. Each dictionary consists of a single NSString object, and then 2 NSArray objects of NSStrings. It looks something like this:

{Name, { array of dates}, {array of dates}}

I understand that NSArray objects are similar to lists, and that NSDictionary objects are similar to records. What I cannot figure out is how to take this list of records that I have created and get that into an AppleScript.

The reason is that I need to use AppleScript to subsequently plug that data into a Microsoft Word Document with a large table. That I already have figured out.

I originally used AS to extract the data from the SQLite database, but as the dbase enlarges, the script takes longer and longer to massage the data into the final form. The command line utility does the massage in under a second. Plus the fact that it has been fun to learn a new tool.

I think my problem comes down to lack of understanding how to generate output from a command line utility. I really only know how to use NSLog to see what is happening, and when I run the utility in Terminal, all the data is displayed on the screen, but when I run the utility in a do shell script, I get a null return.

Anyway, if someone could please point me in the right direction for getting the data generated by the utility into an AS that would be great.

Hi Craig,

I would format the output data already on the Obj-C side.
With NSEnumerator you can easily enumerate arrays and dictionaries and
you can use more than one NSLog or printf statement to print out the result

I can only agree with Stefan, I would also try to format the data in your Obj-C tool. I am also doing a lot of projects where data is collected or produced with command like tools and then further processed with AppleScript to create fancy reports in RagTime. And very often my shell scripts already create a compiled AppleScript containing the data (using osacompile), which is then imported by the workhorse AppleScript to process it.

I found it quite difficult and error-prone to pass data to AppleScript on the command line, especially when the data structures are getting more complex (lists of arrays…). And also parsing the passed data with AppleScript always was a pain for me.

OK, here is where I continue to embarrass myself. I do not really understand what you gentlemen are talking about.

For example, when I use AS to retrieve data directly from an SQLite database, I use something on the order of:

set a to every paragraph of (do shell script "sqlite3 SELECT STATEMENT")

Which produces a nice list of each item returned by the SELECT statement, allowing further processing by the AS code.

What I thought I could do was to create the Obj-C code to do all the heavy lifting, and then send the finished product to stdout, and use a similar type code in AS accessing my command line utility, like this:

set a to every paragraph of (do shell script "/Users/casdvm/bin/iclerkReports")

I am using NSLog to generate output to the Terminal, which yields a screen like this:

Termial OUT = " {
        Name = "Allen, Daniel George";
        dates01 =         (
        );
        dates02 =         (
            "2008-08-31",
            "2008-08-31",
            "2008-09-28"
        );
    },
        {
        Name = "Allen, Diana Kay";
        dates01 =         (
        );
        dates02 =         (
            "2008-08-31",
            "2008-09-28"
        );
    },
""

Although I believe this is indeed stdout, nothing shows up when I call the utility via AS.

Sooooo, when you say this:

and this:

I need a few more details on the mechanics of how to get the data formatted into a form that an AS can handle. I am most intrigued by Martin’s suggestion to use osacompile to create a compiled AppleScript, but I have absolutely no clue how to do it. I have been learning Obj-C for only 6 months, and a lot of this stuff is still pretty hazy to me.

I want to try your suggestions, but I simply do not know how. I apologize for my lack of understanding, but could you proffer a few more details?

In a Foundation Tool it’s better to use printf instead of NSLog, then you will get the result properly with AppleScript.
What format do you prefer for the output? Stdout prints just text. So I recommend to flatten the arrays and dictionaries
with Obj-C to your desired format and print it thru stdout. This is probably much faster than additional AppleScript lines to parse the text

Hi Craig,

I have created a small and very simple sample Python script, that shows my way of transferring data to AppleScript. You can see the code here.

The Python script contains two informations, myage and myname, which are handed over to an imaginary AppleScript calling this Python script. But the Python script does not print both informations to the shell, but rather compiles an AppleScript and only returns the path to this AppleScript (a file named ˜compiled.scpt˜ on your desktop). This way the calling AppleScript doesn’t need to parse the data and can directly import the compiled script with the «load script» command.

My personal experience is, that this approach is often much easier and faster than creating structured output and parsing it with AppleScript. Especially, if you need to return complex data. Sometimes the shell script gathering the data already knows a lot about the types of information. But for the calling AppleScript, everything returned is a string. So how does the AppleScript know, if the returned value of “5” is an integer or a string? Of course, you can return an XML-like structure, but even parsing this in AppleScript can be quite painful…

Ideally, I was hoping for something simpler than it is looking like. I was hoping there was some way to preserve the construction of the NSArray of NSDictionaries and actually generate either a file or a variable that would simply pass a list of records to my chosen AppleScript. I was really, really hoping that someone out there had discovered how to write a file that AS could read as a list. I have saved a multitude of lists and lists of records using the write to file from AS, but I know that those files are pretty unique. Alas, it seems that is not to be.

The problem I am perceiving is what I want to end up with. I want a list of lists: each item containing a string, and two lists of dates associated with each string. I believe it would be easy to generate some kind of creative stdout from my final array and use printf to get that. I just need to ponder that for a bit.

I have looked at your python script, and although I am pretty sure I don’t really need to know python (which I do not know) to understand this, I am still confused. Do I just save this my bin folder and run it? (I have not tried it yet, but I am not afraid to do so.) Do I create the compiled.scpt on my Desktop and use a do shell script to run this? I apologize for being so thick about this, but I am extremely curious, and I do truly enjoy learning new things, but it does take me a while sometimes to figure them out. Please do not be upset or frustrated; I am not a trained programmer. I really would like to explore this option further, I just need a bit more explanation of the mechanics involved.

Thank you both very, very much.

As mentioned above, stdout writes TEXT, nothing else.
Remember, even when you’re reading an array or dictionary from a plist file with defaults read, you get TEXT.

I haven’t tested it, but you could write a plain text file from Obj-C via NSAppleScript using the write as list or as record command
and read the file within AppleScript.

But I guess, it’s faster to flatten the dicts and arrays in Obj-C into some clever text syntax, which can be easily read by AS

Of course the posted script is just an example. Normally I would put such a script inside my AppleScript’s bundle and call it with the «do shell script» command. And being raised as a tidy boy, I would not create the compiled script on the desktop, but in the temporary items folder of the current user («path to temporary items folder from user domain») and remove it after use.

And I can fully understand your frustration. When I first had to query a scientific database for complex informations to create automatic reports with AppleScript, I faced exactly the same problems. That’s why programmers love XML: You can quite easily exchange complex information between multiple platforms and programming languages.

Count me in :slight_smile:

Conceptually this doesn’t sound hard. Rather than the output of the command line utility being on stout, why not write the NSDictionary to a plist file? Then your applescript can read that variable from the plist file and it should come in as a record… or whatever form you wrote to the plist. I haven’t tried it but it should be a straight transfer.

I have a program now that writes a variable to a plist file. It doesn’t matter if that variable is a list, a string, a list of lists etc. The variable will be handled correctly when writing it to a plist file. Then I can read that variable back into my applescript any time and I get the same format back. I’m using the user defaults system in an applescript studio app for this but it should work just as well with the “defaults read” and the “defaults write” shell commands.

It should work… I think :smiley: