TweetFollow Us on Twitter

Storing and Accessing Data with AppleScript

Volume Number: 22 (2006)
Issue Number: 3
Column Tag: Programming

AppleScript Essentials

Storing and Accessing Data with AppleScript

by Benjamin S. Waldie

In last month's column, I provided an introduction to Database Events, a new technology that made its debut with Mac OS X Tiger. I discussed how Database Events can be used as a method of data storage and retrieval by allowing AppleScript to interact directly with SQLite databases.

In this month's column, I would like to discuss some other methods of storage and retrieval, such as accessing properties directly within scripts, or within property list files in the operating system.

Script Properties

The first mechanism for data storage that I would like to address is a script property. When scripting an application, many times, a class within that application will possess properties, or attributes that are accessible through AppleScript. For example, in the Finder, the disk class possesses a number of properties, including a name, capacity, and format. When writing a script, you can define properties for your script itself. A script property is defined within a script using the following syntax:

property propertyName : "Property Value"

For example:

property theUserName : "bwaldie"

Script properties may be defined anywhere within the top level of a script (or a script object). Once a property has been defined, it becomes global in nature, and is accessible both throughout the top level of the script, as well as throughout any handlers in the script.

When a script property is defined, its value is officially assigned when the script is compiled. This means that there is no need to define a value for the property, as you would a variable, within your script's executable code. Rather, you may immediately begin referring to the property.

Script properties are accessible in the same way that variables are accessible. You may get the value of a property and you may set the value of a property in the same way that you would do with a variable. Unlike local variables, however, properties are global in nature. This means that the property is accessible at any level of a script - at the top level, and also within any handlers. For example, after defining the property in the previous example code, the following code would be valid executable code at any level of the script, and would not generate an error indicating that propertyName is not defined.

display dialog propertyName

Properties also retain their most recent values between script executions, and will continue to do so until the script is recompiled. This makes properties an ideal mechanism for storing and retrieving data, so long as the script does not need to be frequently recompiled.

Working with a Property in a Script

Let's take a look at a property in action. The following example code demonstrates how a property can be used to store a persistent value between script executions.

property theRunCount : 0

set theRunCount to theRunCount + 1
display dialog "This script has been run " & theRunCount & " time(s)."

If you run the previous code in Script Editor, the first time the script is run, a dialog will be displayed indicating that the script has been run one time. If you then run the script again, the dialog will indicate that the script has been run two times. If you run it again, the dialog will indicate that the script has been run three times. This will continue indefinitely until the script is recompiled. If you do recompile the script and run it again, the script will start over, indicating that it has been run one time.

To quickly recap what is occurring in this code, the first line of the script defines a property, named theRunCount. The second line changes the value of the property by incrementing its value by one. The third line displays a dialog message that includes the new property value. This new property value is then retained by the script until the next execution, when it is incremented again. When the script is recompiled, the original value of 0 is re-assigned to the property.

Properties are a great way to store information such as commonly requested file or folder paths, usernames, run counts, last execution dates, and more.

    IMPORTANT: Please be aware that properties that are assigned in AppleScript Studio projects are NOT persistent between script executions.

Working with a Property in Another Script

Now that we have discussed storing and accessing properties within a script, let's take the concept one step further - storing and accessing properties in another script. First, create a new document in Script Editor, and enter the following code:

property theRunCount : 0

Next, save the script to the desktop, and name it Properties.scpt. Now, create a new Script Editor document, and enter the following code:

set thePropertyScriptPath to (path to desktop folder as string) & "Properties.scpt"
set thePropertyScript to load script file thePropertyScriptPath
set thePreviousRunCount to (theRunCount of thePropertyScript)
set theNewRunCount to thePreviousRunCount + 1
set theRunCount of thePropertyScript to theNewRunCount
store script thePropertyScript in file thePropertyScriptPath with replacing
display dialog "This script has been run " & theNewRunCount & " time(s)."

Now save this second script to the desktop, and name it External Run Count.scpt. See figure 1.


Figure 1. Accessing a Property from an External Script

If you run the External Run Count.scpt script multiple times, you will encounter behavior similar to that of my earlier examples. The script will display a dialog indicating how many times the script has been triggered. However, this value is not being stored internally. Rather, it is being stored externally in another script.

In the example above, the external script, Properties.scpt, is being loaded by the script External Run Count.scpt. The value of the property theRunCount is being retrieved, and changed within the loaded script. The modified loaded script is then being stored back into its original file, for the next execution.

There are many benefits to utilizing properties in this manner. Let's say, for example, that you have a script that you have created and saved as a run-only application. However, you want others to have the ability to change certain behavioral aspects of that script. You could create properties that control those behaviors, and store them in a separate, editable script. Then, your main script could load and access those properties as needed, during execution. I use this technique frequently when delivering scripts that may not have configurable user interfaces to clients. While the main code of my script may be locked, the client usually has the ability to change certain aspects of how the script behaves by modifying properties in an external script "settings" file.

Property List Files

The next mechanism that I would like to discuss for data storage and retrieval is property list files in Mac OS X, a.k.a. pList files. Property list files are XML-based files, which are utilized by many applications and processes in Mac OS X for storing and retrieving information.

In the past, I have mentioned an application named System Events, which is located in the System > Library > CoreServices folder in Mac OS X. System Events is a background application, which provides scriptable access to many aspects of Mac OS X. With the release of Mac OS X Tiger, Apple has introduced a new suite of terminology into the System Events application - a Property List Suite. See figure 2.


Figure 2. System Events' Property List Suite

The Property List Suite in System Events provides AppleScript with a way to retrieve and modify values within property list files.

Creating a New Property List File

Before getting started with the actual scripting terminology, let me first mention creating property list files. Unfortunately, at present, System Events does not provide a way to create property list files via AppleScript. The intention at this point is to provide a way for scripters to interact with existing property list files.

That said, inevitably, AppleScripters want the ability to create property list files. So, until that functionality is built into System Events (assuming it will be at some point in the future), here is some example code for creating a basic property list file with AppleScript. The code below will write the base XML of an empty property list file to a new text file on the desktop. Feel free to adjust this code as needed in order to meet your specific needs.

set theEmptyPListData to "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict/>
</plist>"

set theOutputFolder to path to desktop folder as string
set thePListPath to theOutputFolder & "myPListFile.plist"
set thePListFile to open for access thePListPath with write permission
set eof of thePListFile to 0
write theEmptyPListData to thePListFile starting at eof
close access thePListFile

Adding New Properties to a Property List File

If you need to generate property list files through scripting, then you probably also need the ability to add new properties to those files. Again, I'm sorry to say that, unfortunately, this is not the most straight-forward process with System Events. As mentioned previously, System Events is intended to provide a way for you to be able to access and modify existing properties. At present, it is not really intended for creating property list files or adding new properties. However, there is a way to do it, and here it is.

In System Events, the Property List Suite consists of two classes, a property list file and a property list item. The property list file class has a contents property, which consists of a property list item class. This property list item class possesses kind, name, and value properties. Out of these, value is the only modifiable property. To add a new property list item within the contents of a property list file, you need to set the value of this property list item to an AppleScript record. This AppleScript record must consist of one or more field names and values, which correspond to XML keys and values, respectively. For example:

set theOutputFolder to path to desktop folder as string
set thePListPath to POSIX path of (theOutputFolder & "myPListFile.plist")
tell application "System Events"
   tell property list file thePListPath
      tell contents
         set value to {|keyName|:"keyValue"}
      end tell
   end tell
end tell

After running the code above, a new property would be generated as XML within the referenced property list file, and would appear as follows:

<dict>
   <key>keyName</key>
   <string>keyValue</string>
</dict>

You can also use a similar technique to add to property list files that already contain existing properties. The following example code demonstrates how this can be done.

set theOutputFolder to path to desktop folder as string
set thePListPath to POSIX path of (theOutputFolder & "myPListFile.plist")
tell application "System Events"
   tell property list file thePListPath
      tell contents
         set previousValue to value
         set value to (previousValue & {|keyName2|:"keyValue2"})
      end tell
   end tell
end tell

In the example code above, first, the existing value of the property list file's content is retrieved. Next, a new AppleScript record is appended to that value. The revised value is then reapplied to the property list file. The resulting XML of the property list file appears as follows:

<dict>
   <key>keyName</key>
   <string>keyValue</string>
   <key>keyName2</key>
   <string>keyValue2</string>
</dict>

In the previous two examples, I have demonstrated how to create property list items that contain string values. There are other types of values that can be created in property list files, including booleans, dates, lists, records, etc. Here, is another example of code that will append a new property to a property list file. This time, a record will be added.

set theOutputFolder to path to desktop folder as string
set thePListPath to POSIX path of (theOutputFolder & "myPListFile.plist")
tell application "System Events"
   tell property list file thePListPath
      tell contents
         set previousValue to value
         set value to (previousValue & {|keyName3|:{subKeyName1:"subKeyValue1", 
            subKeyValue2:"subKeyValue2"}})
      end tell
   end tell
end tell

The above example code would change the contents of the property list file to appear as follows:

<dict>
   <key>keyName</key>
   <string>keyValue</string>
   <key>keyName2</key>
   <string>keyValue2</string>
   <key>keyName3</key>
   <dict>
      <key>subkeyname1</key>
      <string>subKeyValue1</string>
      <key>subkeyvalue2</key>
      <string>subKeyValue2</string>
   </dict>
</dict>

Modifying Properties in a Property List File

Once properties exist within a property list file, the values of these properties may be modified using System Events. The following example code demonstrates how to modify the value of a property that was created in the previous example:

set theOutputFolder to path to desktop folder as string
set thePListPath to POSIX path of (theOutputFolder & "myPListFile.plist")
tell application "System Events"
   tell property list file thePListPath
      tell contents
         set value of property list item "keyName" to "New Key Value"
      end tell
   end tell
end tell

Once the specified property has been modified, its new value will be reflected immediately in the property list file. For example:

<dict>
   <key>keyName</key>
   <string>New Key Value</string>
   <key>keyName2</key>
   <string>keyValue2</string>
   <key>keyName3</key>
   <dict>
      <key>subkeyname1</key>
      <string>subKeyValue1</string>
      <key>subkeyvalue2</key>
      <string>subKeyValue2</string>
   </dict>
</dict>

Likewise, property list items contained within other property list items may also be modified. In doing so, you must be sure to refer to these property list items within their proper containment hierarchy. The following example code demonstrates how to change the value of a property list item within another property list item.

set theOutputFolder to path to desktop folder as string
set thePListPath to POSIX path of (theOutputFolder & "myPListFile.plist")
tell application "System Events"
   tell property list file thePListPath
      tell contents
         set value of property list item "subKeyName1" of property list item 
            "keyName3" to "New Key Value"
      end tell
   end tell
end tell

After running the previous code, the property list file's content would appear as follows:

<dict>
   <key>keyName</key>
   <string>New Key Value</string>
   <key>keyName2</key>
   <string>keyValue2</string>
   <key>keyName3</key>
   <dict>
      <key>subkeyname1</key>
      <string>New Key Value</string>
      <key>subkeyvalue2</key>
      <string>subKeyValue2</string>
   </dict>
</dict>

Retrieving Properties From a Property List File

As you might expect, retrieving a property value from a property list file is relatively straightforward. For example:

set theOutputFolder to path to desktop folder as string
set thePListPath to POSIX path of (theOutputFolder & "myPListFile.plist")
tell application "System Events"
   tell property list file thePListPath
      tell contents
         value of property list item "keyName"
      end tell
   end tell
end tell
--> "New Key Value"

One thing that I do want to stress is, when working with property list files, you do not need to access only property list files that you have created. You may actually use System Events to retrieve and/or modify the values of the property list files of other applications or processes.

For example, the code below demonstrates how to retrieve the value for one of Safari's preferences. In particular, this code will retrieve the value of the AlwaysShowTabBar preference, which indicates whether the tab bar should be displayed in Safari.

set thePListFolderPath to path to preferences folder from user domain as string
set thePListPath to thePListFolderPath & "com.apple.Safari.plist"

tell application "System Events"
   tell property list file thePListPath
      tell contents
         value of property list item "AlwaysShowTabBar"
      end tell
   end tell
end tell
--> true

Storing Properties in an AppleScript Studio Project

Next, I'd like to touch briefly on AppleScript Studio. Earlier, I mentioned that AppleScript Studio does not have the ability to store persistent property values between script executions. However, in many cases, this may not be necessary anyway. The reason for this is because AppleScript Studio actually provides terminology for accessing properties in the application's property list file directly. This is done by accessing the user defaults class of the application class, which may contain default entry classes as elements. These default entry classes may be created and modified within the context of the user defaults class as needed during the execution of your script. Once the application quits, any default entries will be written to the property list file for the application, where they will be accessible the next time the application runs.

The following example code demonstrates how user defaults and default entries may be used to store information.

on launched theObject
   if (default entry "theRunCount" of user defaults exists) = false then
      make new default entry at end of default entries of user defaults with 
      properties {name:"theRunCount", contents:0}
   end if
   idle
end launched

on idle
   set theRunCount to contents of default entry "theRunCount" of user defaults
   set theNewRunCount to theRunCount + 1
   display dialog "This script has been run " & theNewRunCount & " time(s)."
   set contents of default entry "theRunCount" of user defaults to theNewRunCount
   quit
end idle

In the on launched handler above, an if statement is used to determine whether a default entry named theRunCount already exists in the user defaults. If it does not, then it is created with an initial contents value of 0.

When the on idle handler triggers, the run count default entry is retrieved from the user defaults, incremented, and displayed in a dialog. The incremented run count is then applied back to the appropriate default entry in the user defaults. When the application quits, this information is stored in the property list file for the application. Therefore, if this application is triggered multiple times, the run count value will continue to increment with each new execution.

User defaults provide yet another way to store and access data during script execution, though only in AppleScript Studio projects.

Other Options

I would like to also take a moment to mention that there are other ways that you may choose to store and retrieve data, should you decide that the methods mentioned previously do not meet your needs in a particular situation. One way is to store data in a standard text file of some type. Typically, a delimited format of some type makes a good choice, although it may require that you write some fancy parsing code. Another choice could be to store your data in a database, such as FileMaker Pro. If you're using Mac OS X 10.4 or higher, then you could also consider exploring Database Events further, which was the topic of last month's column.

In Closing

Hopefully, I have been able to provide some insight into several possible methods of data storage. Obviously, you are certainly not bound to make use of only the techniques that I discussed. There are other mechanisms, which I encourage you to explore. However, the techniques that I have mentioned are the most commonly used among scripters, and generally do provide you with a variety of relatively quick and easy ways to store and retrieve data using AppleScript.

Until next time, keep scripting!


Ben Waldie is author of the best selling books "AppleScripting the Finder" and the "Mac OS X Technology Guide to Automator", available from http://www.spiderworks.com. Ben is also president of Automated Workflows, LLC, a firm specializing in AppleScript and workflow automation consulting. For years, Ben has developed professional AppleScript-based solutions for businesses including Adobe, Apple, NASA, PC World, and TV Guide. For more information about Ben, please visit http://www.automatedworkflows.com, or email Ben at applescriptguru@mac.com.

 
AAPL
$93.94
Apple Inc.
-0.49
MSFT
$44.84
Microsoft Corpora
+0.15
GOOG
$589.47
Google Inc.
-5.61

MacTech Search:
Community Search:

Software Updates via MacUpdate

OS X Yosemite 10.10 DP4 - Developer Prev...
Note: This is a Developer Preview. You must be a registered Apple Mac Developer to download this update. OS X Yosemite is Apple's newest operating system for Mac. An elegant design that feels... Read more
FinderPop 2.5.6 - Classic Mac utility, n...
FinderPop is a Universal preference pane that extends OS X's contextual menus using a FinderPop Items folder much as the Apple Menu Items folder used to do for the Apple menu. It has other features... Read more
SpiderOak 5.1.7 - Secure cloud backup, s...
SpiderOak is a multi-platform secure online backup, storage, access, and sharing solution engineered for the consumer and small businesses. You must first sign up to use SpiderOak. Running natively... Read more
Espionage 3.6 - Simple, state of the art...
Espionage offers state-of-the-art encryption and plausible deniability for your confidential data. Sometimes, encrypting your data isn't enough to protect it. That's why Espionage 3 goes beyond data... Read more
calibre 1.45.0 - Complete e-library mana...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital... Read more
iFFmpeg 4.3.1 - Convert multimedia files...
iFFmpeg is a graphical front-end for FFmpeg, a command-line tool used to convert multimedia files between formats. The command line instructions can be very hard to master/understand, so iFFmpeg does... Read more
Chromium 36.0.1985.125 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. FreeSMUG-Free OpenSource Mac User Group build is... Read more
pwSafe 3.0 - Secure password management...
pwSafe provides simple and secure password management across devices and computers. pwSafe uses iCloud to keep your password databases backed-up and synced between Macs and iOS devices. It is... Read more
Day One 1.9.6 - Maintain a daily journal...
Day One is the easiest and best-looking way to use a journal / diary / text-logging application for the Mac. Day One is well designed and extremely focused to encourage you to write more through... Read more
Google Chrome 36.0.1985.125 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more

Latest Forum Discussions

See All

HELMUT Review
HELMUT Review By Andrew Fisher on July 21st, 2014 Our Rating: :: TRUNDLE SIMULATOR 2014Universal App - Designed for iPhone and iPad HELMUT is a fun, fleeting time-sink that offers a momentary distraction and nothing else.   | Read more »
Walkr Review
Walkr Review By Jennifer Allen on July 21st, 2014 Our Rating: :: ORIGINAL WALKINGiPhone App - Designed for the iPhone, compatible with the iPad Walking is a bit more exciting thanks to this planet building/discovering sim reliant... | Read more »
Zombie Commando Review
Zombie Commando Review By Jennifer Allen on July 21st, 2014 Our Rating: :: MINDLESS SLAUGHTERUniversal App - Designed for iPhone and iPad Briefly fun but ultimately forgettable, Zombie Commando will scratch an itch then be... | Read more »
Swords & Poker Adventures Review
Swords & Poker Adventures Review By Jennifer Allen on July 21st, 2014 Our Rating: :: SOULLESS POKER PLAYUniversal App - Designed for iPhone and iPad Swords & Poker Adventures is a mishmash of Poker and RPGing, but it lacks... | Read more »
Warhammer 40,000: The Horus Heresy: Drop...
Warhammer 40,000: The Horus Heresy: Drop Assault Coming Soon to iOS Posted by Jennifer Allen on July 21st, 2014 [ permalink ] Coming soon to iOS will be an all-new Warhammer 40,000 tactical strategy game by the name of The Horus Heresy: Drop As | Read more »
A Life Worth Dying For Review
A Life Worth Dying For Review By Jordan Minor on July 21st, 2014 Our Rating: :: A BEAUTIFUL MINDUniversal App - Designed for iPhone and iPad A Life Worth Dying For is a fascinating portrait of a serious subject.   | Read more »
Zombie Puzzle Panic Review
Zombie Puzzle Panic Review By Jordan Minor on July 21st, 2014 Our Rating: :: THE MATCHING DEADUniversal App - Designed for iPhone and iPad Zombie Puzzle Panic puts some pretty neat undead twists on Match-3 puzzling.   | Read more »
This Week at 148Apps: July 14-18, 2014
Expert App Reviewers   So little time and so very many apps. What’s a poor iPhone/iPad lover to do? Fortunately, 148Apps is here to give you the rundown on the latest and greatest releases. And we even have a tremendous back catalog of reviews; just... | Read more »
Fallen Lords Review
Fallen Lords Review By Andrew Fisher on July 18th, 2014 Our Rating: :: FALLS SHORTiPad Only App - Designed for the iPad Fallen Lords is a decent game, but its similarity and inferiority compared to Ghost Stories makes it ultimately... | Read more »
Real Boxing’s New Combo Update is a Knoc...
Real Boxing’s New Combo Update is a Knockout Posted by Blake Grundman on July 18th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »

Price Scanner via MacPrices.net

Twelve South HiRise For MacBook – Height-Adju...
If you use your MacBook as a workhorse desktop substitute, as many of us do, a laptop stand combined with an external keyboard and pointing device are pretty much obligatory if you want to avoid... Read more
Why The Mac Was Not Included In The Apple/IBM...
TUAW’s Yoni Heisler cites Fredrick Paul of Network World whoi blogged last week that the Mac’s conspicuous absence from Apple and IBM’s landmark partnership agreement represents a huge squandered... Read more
Save $100 on 13-inch Retina MacBook Pros, plu...
Adorama has 13″ Retina MacBook Pros on sale for $100 off MSRP. Shipping is free, and Adorama charges sales tax in NY & NJ only: - 13″ 2.4GHz/128GB MacBook Pro with Retina Display: $1199 - 13″ 2.... Read more
Blurr it 2.3 for iOS – Quickly Blurs Selected...
Hyderabad, India based TouchLabs has announced a new update of Blurr it 2.3, their photography app for iOS users. Blurr it allows you to blur part of the image to hide potentially sensitive or... Read more
MacBook Airs on sale for $100 off MSRP, start...
Best Buy has the new 2014 MacBook Airs on sale for up to $100 off MSRP on their online store. Choose free home shipping or free local store pickup (if available). Prices valid for online orders only... Read more
Amazon Announces Kindle Unlimited: Unlimited...
Amazon.com has introduced Kindle Unlimited — a new subscription service which allows customers to freely read as much as they want from over 600,000 Kindle books, and listen as much as they want to... Read more
New Linksys Wireless Range Extenders Boost Wi...
Linksys has announced its new lineup of Linksys Wi-Fi Range Extenders. Consumers often experience a weak wireless signal in some parts of their house or apartment caused by blocking elements such as... Read more
MacBook Airs available starting at $719
The Apple Store has Apple Certified Refurbished 2013 & 2012 MacBook Airs in stock today starting at $719. An Apple one-year warranty is included with each MacBook, and shipping is free: 2013... Read more
Get the best deals on iPad minis with Apple r...
The Apple Store has Certified Refurbished 2nd generation iPad minis with Retina Displays available for up to $130 off the cost of new models, starting at $339. Apple’s one-year warranty is included... Read more
Best Buy’s College Student Deals: $100 off Ma...
Take an additional $100 off all MacBooks and iMacs, $50 off iPad Airs and iPad minis, at Best Buy Online with their College Students Deals Savings, valid through July 25th. Anyone with a valid .EDU... Read more

Jobs Board

*Apple* Computer Technician - Fairfield Coun...
Company DescriptionWe are an Apple Authorized Sales and Service Provider. We have been selling and servicing Apple computers in the Fairfield County area for over 20 Read more
*Apple* Computer Technician - Fairfield Coun...
Company DescriptionWe are an Apple Authorized Sales and Service Provider. We have been selling and servicing Apple computers in the Fairfield County area for over 20 Read more
Mac Expert - *Apple* Online Store Mexico -...
…MUST be fluent in English and Spanish to be considered for this position At Apple , we believe that hard work, a fun environment, creativity and innovation fuel the Read more
*Apple* Computer Technician - Fairfield Coun...
Company DescriptionWe are an Apple Authorized Sales and Service Provider. We have been selling and servicing Apple computers in the Fairfield County area for over 20 Read more
Mac Expert - *Apple* Online Store - Apple (...
**Job Summary** At Apple , we believe that hard work, a fun environment, creativity and innovation fuel the ultimate customer experience. We believe each customer Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.