How to fetch and parse an XML file using AppleScript? - applescript

There's an XML file on some remote server (http://foo/bar.xml):
<?xml version="1.0" encoding="UTF-8"?>
<foo>
bar
</foo>
How can I get the value "bar" using AppleScript?

Here's what I've done:
set file_tgt to (POSIX path of (path to temporary items)) & "file.xml"
do shell script "curl -L " & "http://url.com/file.xml" & " -o " & file_tgt
tell application "System Events"
set file_content to contents of XML file file_tgt
tell file_content
set my_value to value of XML element 1
end tell
end tell
Originally I was using the "URL Access Scripting" app to fetch the file, but since it has been removed in Lion, I switched to pure curl, which works under both Snow Leopard and Lion.

I found this thread which has an example of parsing an XML file with the XML tools available via System Events. Seems pretty convoluted to me though.
There's also this (freeware) scripting addition package for parsing/writing XML. Haven't looked at it, but it might be neat.
Personally, I would save my script as a script bundle, and then I'd make a little php/Ruby/perl/python/whatever script to parse the XML (since I'm just more comfortable with that) in the bundle. Then I'd use AppleScript then pass the XML to the parser script from cURL.
AppleScript:
set scriptPath to POSIX path of (path to me as alias) & "Contents/Resources/parse_xml.rb"
set fooValue to do shell script "curl http://foo/test.xml 2> /dev/null | ruby " & quoted form of scriptPath
parse_xml.rb could be somthing like this (using Ruby as an example):
require "rexml/document"
# load and parse the xml from stdin
xml = STDIN.read
doc = REXML::Document.new(xml)
# output the text of the root element (<foo>) stripped of leading/trailing whitespace
puts doc.root.text.strip
(Ruby and the REXML package should be readily available on any Mac, so it should work anywhere… I believe)
Point is, when the script runs it'll download the XML file with cURL, pass it to the Ruby script, and in the end, fooValue in the AppleScript will be set to "bar".
Of course, if the XML is more complex, you'll need more scripting, or take another look at the other options.
There are probably even more ways of doing it (for instance, you could just do some string manipulation instead of full-on XML parsing, but that's a little brittle of course), but I'll stop here :)

Realizing this is an old question, but here’s one way using the Bing Maps API (note I replaced my API key with XXXXXXXXXX). use do shell script with curl to retrieve the XML, then just walk down the elements until you get to the one you need (you can consolidate all the tells into tell xml element “X” of xml element “y” of xml element…, but this is just easier to follow).
set theXML to make new XML data with properties {name:"Geolocation", text:(do shell script "curl 'http://dev.virtualearth.net/REST/v1/Locations?&q=638%20Brandon%20Town%20Center%20Brandon%20FL%2033511&o=xml&key=XXXXXXXXXX'")}
tell theXML
tell XML element "Response"
tell XML element "ResourceSets"
tell XML element "ResourceSet"
tell XML element "Resources"
tell XML element "Location"
tell XML element "Point"
set theLatitude to the value of XML element "Latitude"
set theLongitude to the value of XML element "Longitude"
end tell
end tell
end tell
end tell
end tell
end tell
end tell
EDIT: I suppose I should include the XML I was using for the above:
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Response xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.microsoft.com/search/local/ws/rest/v1\">
<Copyright>Copyright © 2014 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.</Copyright>
<BrandLogoUri>http://dev.virtualearth.net/Branding/logo_powered_by.png</BrandLogoUri>
<StatusCode>200</StatusCode>
<StatusDescription>OK</StatusDescription>
<AuthenticationResultCode>ValidCredentials</AuthenticationResultCode>
<TraceId>06bb657f1ac9466ba00ef45aa55aef3b|BN20130631|02.00.108.1000|BN2SCH020180822, BN2SCH020181444, BN2SCH020181020, BN2SCH030291220, BN2SCH030261523</TraceId>
<ResourceSets>
<ResourceSet>
<EstimatedTotal>1</EstimatedTotal>
<Resources>
<Location>
<Name>638 Brandon Town Center Dr, Brandon, FL 33511</Name>
<Point>
<Latitude>27.929752349853516</Latitude>
<Longitude>-82.326362609863281</Longitude>
</Point>
<BoundingBox>
<SouthLatitude>27.925889632282839</SouthLatitude>
<WestLongitude>-82.332191670122214</WestLongitude>
<NorthLatitude>27.933615067424192</NorthLatitude>
<EastLongitude>-82.320533549604349</EastLongitude>
</BoundingBox>
<EntityType>Address</EntityType>
<Address>
<AddressLine>638 Brandon Town Center Dr</AddressLine>
<AdminDistrict>FL</AdminDistrict>
<AdminDistrict2>Hillsborough Co.</AdminDistrict2>
<CountryRegion>United States</CountryRegion>
<FormattedAddress>638 Brandon Town Center Dr, Brandon, FL 33511</FormattedAddress>
<Locality>Brandon</Locality>
<PostalCode>33511</PostalCode>
</Address>
<Confidence>High</Confidence>
<MatchCode>Good</MatchCode>
<GeocodePoint>
<Latitude>27.929752349853516</Latitude>
<Longitude>-82.326362609863281</Longitude>
<CalculationMethod>Parcel</CalculationMethod>
<UsageType>Display</UsageType>
</GeocodePoint>
<GeocodePoint>
<Latitude>27.929159164428711</Latitude>
<Longitude>-82.32720947265625</Longitude>
<CalculationMethod>Interpolation</CalculationMethod>
<UsageType>Route</UsageType>
</GeocodePoint>
</Location>
</Resources>
</ResourceSet>
</ResourceSets>
</Response>

Related

AppleScript Keynote hangup after opening a illegal pptx file

first I am a beginner AppleScript developer. and I have searched this question for a long time but no result found. I have an AppleScript to convert ppt files into pdf format. but the script will hangup after it matches a bad ppt file.
the script/keynote will popup a dialog showing "xxx.ppt can't be opened right now" "the file format is invalid".
is there any way to prevent keynote from popping up this kinds of dialog?
below is the sample code, and file is a image file but I changed extension to pptx to simulate an illegle file:
set thefile to POSIX file "/Users/dazhangluo/Downloads/brain-storming.pptx"
tell application "Keynote"
activate
try
set thedoc to open thefile
--display dialog class of thedoc
on error errMessage
--display dialog errMessage
log errorMessage
end try
end tell
There is a command-line tool called exiftool which can inspect files and get their metadata, including the 'file type' tag (using -filetype). There are a variety of ways to install it†. Unlike 'mdls', it isn't easily fooled by the file extension. If you run it on a pptx file, it will include this in its results:
File Type : PPTX
You can then grab the last word to test. This script will loop through the files in the specified folder, use exiftool to extract their file type, and then copy the alias of any matching file to a new list. It then opens each file in keynote. My version of keynote (v8) doesn't let me script anything with powerpoint documents, so you're on your own at that point.
set srcFol to (path to desktop as text) & "presentations" as alias
-- or if you prefer…
-- set srcFol to choose folder
tell application "Finder"
set fList to files of srcFol as alias list
set cleanList to {}
repeat with f in fList
set ppFile to POSIX path of f
set qfFile to quoted form of ppFile
tell me to set exifData to do shell script "/usr/local/bin/exiftool -filetype " & qfFile
if last word of exifData is "PPTX" then
set end of cleanList to contents of f
--> alias "Mac:Users:username:Desktop:presentations:powerpoint1.pptx"
end if
end repeat
end tell
tell application "Keynote"
activate
repeat with pptxFile in cleanList
open pptxFile
-- do whatever
end repeat
end tell
NB † Depending upon where exiftool is installed, you may need to change the path, which you can get with which exiftool.

Embed a bash shell script in an AppleScriptObjC application with Xcode

I have attempted to follow the instructions on this post but I am falling short of understanding how some of the posters instructions work.
I want to be able to package the app with a prewritten bash script and then execute it, but don't follow from Step 4 onwards.
Post writes:
4. Also in your AppleScriptObjC script, add the following where appropriate:
property pathToResources : "NSString" -- works if added before script command
5. Where appropriate, also add the following in your AppleScriptObjC script:
set yourScript to pathToResources & "/yourScriptFile.sh"
-- gives the complete unix path
-- if needed, you can convert this to the Apple style path:
set yourScriptPath to (((yourScript as text) as POSIX file) as alias)`
6. As an aside, you could then open the file for read using
tell application "Finder"
open yourScriptPath
end tell
Questions:
Where do I add the line:
property pathToResources : "NSString"
Do I add which of the following, and where?
set yourScript to pathToResources & "/yourScriptFile.sh"
OR
set yourScriptPath to (((yourScript as text) as POSIX file) as alias)
How is it possible to execute the script itself? The mention As an aside, you could then open the file for read using only covers the Apple style path, it does not cover using the aforementioned style.
Can anyone shed a bit more light on this for me, or post a static copy of a AppDelegate.applescript file that shows how the original poster required the base code to be used? I have tried his method and looked across the internet for the past 3 weeks to no avail. I don't want to have to convert all my code for specific tools from bash scripts into AppleScript, as this would take a lot of work.
I only need to know how to reference to the script file (for example myBashScript.sh) in my app, which would reside in the application and be included by Xcode at time of compilation.
I think you should use the command path to resource <specifiedResource>.
See Standard Additions, path to resource.
You could set it by set myVariableName to path to resource "myBashScript.sh" or just use the command instead of your property so it points always to the right place (a user could move your app while running... lol).
ADDITION:
I did it that way in my AppleScript-Application:
on run_scriptfile(this_scriptfile)
try
set the script_file to path to resource this_scriptfile
return (run script script_file)
end try
return false
end run_scriptfile
Whenever I want to run a script that is bundled within my app I do this:
if my run_scriptfile("TestScript.scpt") is false then error number -128
run_scriptfile(this_scriptfile) returns true when everything worked.
I ended up bringing all the information together and now have a solution.
This takes into consideration the following facts:
firstScript = variable name that points to a script called scriptNumberOne.sh
scriptNumberOne.sh = the script that I have embedded into my application to run
ButtonHandlerRunScript_ = the name of the Received Action in Xcode
pathToResources = variable that points to the internal Resources folder of my application, regardless of it's current location
Using this information, below is a copy of a vanilla AppDelegate.applescript in my AppleScriptObjC Xcode project:
script AppDelegate
property parent : class "NSObject"
property pathToResources : "NSString"
on applicationWillFinishLaunching_(aNotification)
set pathToResources to (current application's class "NSBundle"'s mainBundle()'s resourcePath()) as string
end applicationWillFinishLaunching_
on ButtonHandlerRunScript_(sender)
set firstScript to pathToResources & "/scriptNumberOne.sh"
do shell script firstScript
end ButtonHandlerRunScript_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
end script

can't locate my file in subfolder nor read it (applescript)

I want to read text in a list from a textfile "test.txt" that's located in a subfolder called "data". The text is formatted as plain text, every line ends with enter. After all I want to work around that my code could not be saved anymore because I stored too many data like set names to {"Adam", "Adele",... which pumped the sctp over 500kb, by reading huge lists from textfiles.
Which way I try, I end up getting the xyz.app-name in my set folder, I don't know how its better to use read or do it with POSIX, or I get permission trouble when I use container of to filter my filename, nor where to nest the code to open the file.
Can someone help me start?
EDIT
I tried a bit and got a solution that worked for me, reading my text in a list. See below.
Then I came to another problem: One list I could not save in MacOSRoman, so I had to use Unicode UTF-16. But I can't break myfile2 into a list anymore. Can someone help me out with this?
As a new user I could not upload my screenshot, so here is the code:
set List1 to (read file myFile1 using delimiters linefeed) as list
set List2 to (read file myFile2 using delimiters linefeed as Unicode text) as list
Try any of these:
set aData to read file "Mac OS X:Users:j0k:Desktop:text file.txt"
set bData to read POSIX file "/Users/j0k/Desktop/text file.txt"
set cData to read alias "Mac OS X:Users:j0k:Desktop:text file.txt"
set dData to do shell script "cat '/Users/j0k/Desktop/text file.txt'"
An easy way of getting the path to your file is to drag the file into the script editor.
EDIT:
tell application "Finder" to set myFolder to container of (path to me) as text
set myFile to myFolder & "Data:test.txt"
set aData to read file myFile

Ruby library to read Apple Numbers documents?

There are several Ruby open-source libraries for reading Microsoft Excel files, such as roo or spreadsheet. What about Apple Numbers documents? Is there anything available?
Such a library apparently does not exist (yet?). A good workaround for now is to automate the conversion to CSV through applescript, and then read this result instead of trying to read the Numbers file directly. This might not fit everyone's needs, though, but works perfectly for me.
Here is the applescript:
# -------------------------------------------------------------------------------
# Command-line tool to convert an iWork '09 Numbers
# document to CSV.
#
# Parameters:
# - input: Numbers input file
# - output: CSV output file
#
# Attik System, Philippe Lang
#
# Creation date: 31 mai 2012
# Modification date:
# -------------------------------------------------------------------------------
on run argv
# We retreive the path of the script
set myPath to (path to me)
tell application "Finder" to set myFolder to folder of myPath
# We get the command line parameters
set input_file to item 1 of argv
set output_file to item 2 of argv
# We retreive the extension of the file
set theInfo to (info for (input_file))
set extname to name extension of (theInfo)
# Paths
set input_file_path to (myFolder as text) & input_file
set output_file_path to (myFolder as text) & output_file
if extname is equal to "numbers" then
tell application "Numbers"
open input_file_path
save document 1 as "LSDocumentTypeCSV" in output_file_path
close every window saving no
end tell
end if
end run
Use it like this:
osascript convert_to_csv.scpt input_file.numbers output_file.csv

list subfolders using applescript

This is my first applescript. I thought I'd do something simple like navigating to a folder using a path and listing the subfolders...Unfortunately, I can't figure it out :-)
Here is what I've tried so far:
The first try:
tell application "Finder"
set the_folder to POSIX path of "Users:MyName:Doc"
log the_folder
set folder_list to every item of folder the_folder
log folder_list
end tell
This produces an error:
"Finder got an error: Can't get folder "/Users/MyName/Doc".
Could someone please:
1. Explain to me what I'm doing wrong.
2. Provide an example that works.
Thanks in advance.
btw the folder does exist on my machine...
UPDATE: Oops! It appears that I have given you the wrong information so I will give you the correct information.
The command POSIX path of requires a complete alias reference. By that I mean supplying the full file reference (i.e. <your_disk_name>:Users:<your_user_name>:somefolder:). Make sure that if you're referring to a folder that you end the reference with a colon (i.e. Macintosh HD:Users:). An improved version would look like this:
tell application "Finder"
set the_folder to (POSIX path of ("<your_disk_name>:Users:<your_user_name>:Doc:") as alias) as alias
set folder_list to every item of the_folder
end tell
OPTIONAL
To coerce a POSIX path (i.e. /Users/<your_user_name>/somefolder) back into an alias, two conversions are needed.
Conversion 1: The first step is to convert the reference into a file reference. To do this, place the words as POSIX file after the reference, like so:
"/Users/<your_user_name>/somefolder" as POSIX file
This code procudes a file reference in this form: file "<your_disk_name>:Users:<your_user_name>:somefolder:"
Conversion 2: Add a second coercion, as alias, to the end of the reference...
"/Users/<your_user_name>/somefolder" as POSIX file as alias
This code produces an actual alias reference: alias "<your_disk_name>:Users:<your_user_name>:somefolder:
If you have any questions, just ask. :)
Posix paths are paths you use at the command line and are "/" delimited. Applescript paths are ":" separated so just use those. Try this script to see what the path should look like...
set folderPath to (choose folder) as text

Resources