Parsing Excel Data in Apple Swift
In Mac OS X 10.6 Snow Leopard Apple introduced the AppleScriptObjC framework which makes it very easy to interact between Cocoa and AppleScript. AppleScript code and a Objective-C like syntax can be used in the same source file. It's much more convenient than Scripting Bridge
and NSAppleScript
.
AppleScriptObjC cannot be used directly in Swift because the command loadAppleScriptObjectiveCScripts
of NSBundle is not bridged to Swift.
However you can use a Objective-C bridge class for example
ASObjC.h
@import Foundation;@import AppleScriptObjC;@interface NSObject (Excel)- (void)openExcelDocument:(NSString *)filePath;- (NSArray *)valueOfUsedRange;@end@interface ASObjC : NSObject+ (ASObjC *)sharedASObjC;@property id Excel;@end
ASObjC.m
#import "ASObjC.h"@implementation ASObjC+ (void)initialize{ if (self == [ASObjC class]) { [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts]; }}+ (ASObjC *)sharedASObjC{ static id sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[ASObjC alloc] init]; }); return sharedInstance;}- (instancetype)init{ self = [super init]; if (self) { _Excel = NSClassFromString(@"ASExcel"); } return self;}@end
Create a AppleScript source file form the AppleScriptObjC template
ASExcel.applescript
script ASExcel property parent: class "NSObject" on openExcelDocument:filePath set asFilePath to filePath as text tell application "Microsoft Excel" set sourceBook to open workbook workbook file name asFilePath repeat try get workbooks return end try delay 0.5 end repeat end tell end openDocument on valueOfUsedRange() tell application "Microsoft Excel" tell active sheet set activeRange to used range return value of activeRange end tell end tell end valueOfUsedRangeend script
Link to the AppleScriptObjC framework if necessary.
Create the Bridging Header and import ASObjC.h
Then you can call AppleScriptObjC from Swift with
ASObjC.sharedASObjC().Excel.openExcelDocument("Macintosh HD:Users:MyUser:Path:To:ExcelFile.xlsx")
or
let excelData = ASObjC.sharedASObjC().Excel.valueOfUsedRange() as! Array<[String]>
It's somewhat unclear if you're trying to eliminate Excel as a dependency (which is not unreasonable: it costs money and not everyone has it) or AppleScript as a language (totally understandable, but a bad practical move as Apple's alternatives for application automation all suck).
There are third-party Excel-parsing libraries available for other languages, e.g. I've used Python's openpyxl
(for .xlsx files) and xlrd
(for .xsl) libraries successfully in my own projects. And I see through the magicks of Googles that someone's written an ObjC framework, DHlibxls, which [assuming no dynamic trickery] should be usable directly from Swift, but I've not used it myself so can't tell you anything more.
You can use ScriptingBridge or NSAppleScript to interact with Apple Scriptable stuff
ScriptingBridge can generate a header file from the Apple Script dictionary.
NSAppleScript can execute any AppleScript for you by passing a String