Go Back   MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Dec 18, 2012, 04:39 PM   #1
moonman239
macrumors 65816
 
Join Date: Mar 2009
AppleScript: Set variable to every XML element of a given name

Dear fellow AppleScript programmers,

I have an iOS app that has recipes. Each recipe can be organized by course or by cuisine. Each course and cuisine have their own table view and controller. I need to make sure each recipe is linked to a course and cuisine. Since a storyboard is really an XML file containing all the UI elements, I figured I could create an AppleScript that searches all the table view cells to make sure that all recipes are linked to two table view cells.

Here is my code:

Code:
set the_file to ((choose file without invisibles) as string)
tell application "System Events"
	set xml_data to contents of XML file the_file
	tell xml_data to set tableViewCells to every XML element of xml_data whose name is "tableViewCell"
	tell xml_data to set subViews to every XML element of tableViewCells whose name is "subviews"
	tell xml_data to set viewLinks to every XML element of subViews whose name is "view"
	tell xml_data to set viewControllers to every XML element whose name is "viewController"
	tell xml_data to set views to every XML element of viewControllers whose name is "view"
	tell xml_data to set navItems to first XML element of views whose name is "navigationItem"
	tell xml_data to set recipes to value of XML attribute "title" of XML element navItems
end tell
When I try to run this code, I get the error "Can't get every element of {} whose name = "subviews"". I just don't get why the fourth line of code results in tableViewCells being set to nothing useful. The tag names are correct.

I could do the job myself, but I just don't want to.
__________________
The funny thing about this signature is that by the time you get to the end of it, you will have spent between five and ten seconds doing so.
moonman239 is offline   0 Reply With Quote
Old Dec 18, 2012, 05:23 PM   #2
chown33
macrumors 603
 
Join Date: Aug 2009
What does this error message tell you, or at least what does it suggest to you?
Code:
"Can't get every element of {} whose name = "subviews"".
What it suggests to me is you have an empty array (shown as {} in the error message), so asking for "every element" of an empty array is an impossible request to fulfill.

So work backwards from that, possibly using a debugger.

At the very least, you will need to apply the debugging technique of Break It Down. In this case, that means running the script with as few commands as possible, then looking carefully at each result. For example, the starting point is probably something like:
Code:
set the_file to ((choose file without invisibles) as string)
tell application "System Events"
  set xml_data to contents of XML file the_file
  return xml_data
end tell
If you have an AppleScript debugging tool, you might have other techniques you can apply. Otherwise you're going to have to do the equivalent of single-stepping, which means you need to start from the smallest thing that works (e.g. the above example), then gradually add things until it breaks.

Another possibility might be to use some other scripting language that can parse XML, yet gives you better debugging capability.


Not sure what you mean by not wanting to do the job yourself. If you're referring to not wanting to find the problem by yourself, then what would someone else need in order to start finding the problem for you?
chown33 is offline   0 Reply With Quote
Old Dec 18, 2012, 10:14 PM   #3
ytk
macrumors regular
 
Join Date: Jul 2010
Don't use AppleScript for this. The only real use for AppleScript is communicating with applications that support AppleScript. If you have experience with any other programming language that can do XML easily (e.g., Ruby, Python, Perl) you'll find it much simpler, faster, and more robust to write it in that language. My guess is that you'd be able to install any needed XML modules for your chosen language, figure out how to use them, and write, test, and fully debug your program before you got any sort of XML parsing working flawlessly in AppleScript.

Heck, even if you have to learn the entire language starting with "Hello World", you might still be able to do it more quickly than with AppleScript.
ytk is offline   0 Reply With Quote
Old Jan 1, 2013, 02:19 PM   #4
moonman239
Thread Starter
macrumors 65816
 
Join Date: Mar 2009
Quote:
Originally Posted by chown33 View Post
What does this error message tell you, or at least what does it suggest to you?
Code:
"Can't get every element of {} whose name = "subviews"".
What it suggests to me is you have an empty array (shown as {} in the error message), so asking for "every element" of an empty array is an impossible request to fulfill.

So work backwards from that, possibly using a debugger.

At the very least, you will need to apply the debugging technique of Break It Down. In this case, that means running the script with as few commands as possible, then looking carefully at each result. For example, the starting point is probably something like:
Code:
set the_file to ((choose file without invisibles) as string)
tell application "System Events"
  set xml_data to contents of XML file the_file
  return xml_data
end tell
If you have an AppleScript debugging tool, you might have other techniques you can apply. Otherwise you're going to have to do the equivalent of single-stepping, which means you need to start from the smallest thing that works (e.g. the above example), then gradually add things until it breaks.

Another possibility might be to use some other scripting language that can parse XML, yet gives you better debugging capability.


Not sure what you mean by not wanting to do the job yourself. If you're referring to not wanting to find the problem by yourself, then what would someone else need in order to start finding the problem for you?
OK, for some reason, "set tableViewCells to every XML element of xml_data whose name is "tableViewCell"" returns an empty array.

----------

Quote:
Originally Posted by ytk View Post
Don't use AppleScript for this. The only real use for AppleScript is communicating with applications that support AppleScript. If you have experience with any other programming language that can do XML easily (e.g., Ruby, Python, Perl) you'll find it much simpler, faster, and more robust to write it in that language. My guess is that you'd be able to install any needed XML modules for your chosen language, figure out how to use them, and write, test, and fully debug your program before you got any sort of XML parsing working flawlessly in AppleScript.

Heck, even if you have to learn the entire language starting with "Hello World", you might still be able to do it more quickly than with AppleScript.
I kind of like using AppleScript for things like this.
__________________
The funny thing about this signature is that by the time you get to the end of it, you will have spent between five and ten seconds doing so.
moonman239 is offline   0 Reply With Quote
Old Jan 1, 2013, 02:45 PM   #5
chown33
macrumors 603
 
Join Date: Aug 2009
Quote:
Originally Posted by moonman239 View Post
OK, for some reason, "set tableViewCells to every XML element of xml_data whose name is "tableViewCell"" returns an empty array.
The first step for someone who wants to assist you would be for them to replicate what you're seeing. To do that, they would need the same data you have. That is, the same XML file or files.

Without the same data, no one can replicate what you're seeing, and no one can explain what you're seeing because no one knows the structure of your XML. So unless you post your actual XML data, no one can explain it.

This is what I was trying to get at when I asked you the question, "What would someone else need in order to start finding the problem for you?". The answer is, they would need your XML data. You've already posted your AppleScript code, but without the XML that code is trying to act on, the code by itself is useless.
chown33 is offline   0 Reply With Quote
Old Jan 1, 2013, 04:30 PM   #6
moonman239
Thread Starter
macrumors 65816
 
Join Date: Mar 2009
Quote:
Originally Posted by chown33 View Post
The first step for someone who wants to assist you would be for them to replicate what you're seeing. To do that, they would need the same data you have. That is, the same XML file or files.

Without the same data, no one can replicate what you're seeing, and no one can explain what you're seeing because no one knows the structure of your XML. So unless you post your actual XML data, no one can explain it.

This is what I was trying to get at when I asked you the question, "What would someone else need in order to start finding the problem for you?". The answer is, they would need your XML data. You've already posted your AppleScript code, but without the XML that code is trying to act on, the code by itself is useless.
I don't really think I need to do that. You could probably replicate it by making some arbitrary XMLL file with a bunch of elements with the name "tableViewCell"

Anyways, I'm currently working on some code that will do the trick. I found out that I can tell an XML element to do whatever I want it to. So the code I'm building will accomplish the same task by removing all XML elements except the one it's currently working with, then putting them back in.
__________________
The funny thing about this signature is that by the time you get to the end of it, you will have spent between five and ten seconds doing so.
moonman239 is offline   0 Reply With Quote
Old Jan 1, 2013, 04:54 PM   #7
chown33
macrumors 603
 
Join Date: Aug 2009
Quote:
Originally Posted by moonman239 View Post
I don't really think I need to do that. You could probably replicate it by making some arbitrary XMLL file with a bunch of elements with the name "tableViewCell"
No one knows what your XML tags are. We could guess what the proper XML structure is based on your AppleScript code, but why?

It's up to you to post the code and data that causes the problem. If you want to make (and test) an example XML file with the requisite structure that shows the problem, then please do that and post the fail-case.

http://www.mikeash.com/getting_answers.html
chown33 is offline   1 Reply With Quote
Old Jan 1, 2013, 05:54 PM   #8
moonman239
Thread Starter
macrumors 65816
 
Join Date: Mar 2009
OK, I've hit a roadblock.

Like I said before, I need to isolate one element from the pack at a time. To help me do that, I have a function I can use to remove a piece of text from a string and output the modified string. Obviously, this function doesn't work on XML files. This function is to be called by another function, which will go through all the elements of a given name and tell them to run the code I want them to run.

UPDATE: I'm going in the wrong direction.
__________________
The funny thing about this signature is that by the time you get to the end of it, you will have spent between five and ten seconds doing so.
moonman239 is offline   0 Reply With Quote
Old Jan 1, 2013, 06:43 PM   #9
moonman239
Thread Starter
macrumors 65816
 
Join Date: Mar 2009
Update on my progress toward a solution:

Code:
on removeText(parentString, childString, occurrencesToExclude)
	set oldDelims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to childString
	set textItems to every text item of parentString
	set AppleScript's text item delimiters to oldDelims
	if occurrencesToExclude is not missing value then
		repeat with I from 1 to length of textItems
			if occurrencesToExclude contains I then
				set item I of textItems to item I of textItems & childString
			end if
		end repeat
	end if
	set newString to textItems as string
	return newString
end removeText
on tellEveryXMLElementWithName(elementContainer, elementName, code)
	set XMLContents to (read elementContainer)
	set newContainer to removeText(XMLContents, elementName, 1)
	tell elementName
		run script code
	end tell
end tellEveryXMLElementWithName

set the_file to (choose file without invisibles) as string
tell application "System Events"
	set file1 to XML file the_file
	tell file1
		set code to "set X to 0"
		my tellEveryXMLElementWithName(file1, "tableViewCell", code)
	end tell
end tell
It seems I can't perform a "read" operation on an XML file. What I want to do is create a function that others can use without doing anything besides calling it.
__________________
The funny thing about this signature is that by the time you get to the end of it, you will have spent between five and ten seconds doing so.
moonman239 is offline   0 Reply With Quote
Old Jan 1, 2013, 09:28 PM   #10
ytk
macrumors regular
 
Join Date: Jul 2010
Quote:
Originally Posted by moonman239 View Post
I kind of like using AppleScript for things like this.
And two weeks later, you're still struggling to debug a program that would take ten minutes to write in some other language. Suit yourself!
ytk is offline   1 Reply With Quote
Old Jan 2, 2013, 01:27 PM   #11
moonman239
Thread Starter
macrumors 65816
 
Join Date: Mar 2009
Quote:
Originally Posted by ytk View Post
And two weeks later, you're still struggling to debug a program that would take ten minutes to write in some other language. Suit yourself!
I have Xcode. I just don't want to build a full-on app with GUI and everything, as my script won't be very fancy. I also don't want to download something else to do this.
__________________
The funny thing about this signature is that by the time you get to the end of it, you will have spent between five and ten seconds doing so.
moonman239 is offline   0 Reply With Quote
Old Jan 2, 2013, 02:42 PM   #12
ytk
macrumors regular
 
Join Date: Jul 2010
You don't have to do any of that. You can write the program in Ruby, Python, or Perl (all of which are already installed on every single Mac out there), and simply execute it from the command line. It doesn't need to have a GUI or anything at all. Or you can easily bake it into an application using Platypus, which lets you turn any program or shell script into a launchable app (with drag and drop support and everything) with just a few clicks. Heck, you can even call AppleScript from within your program, in case you want to use the communication functions or the rudimentary dialog boxes it provides.

AppleScript has its uses. I use it all the time, actually—mainly calling it from within Ruby scripts to automate tedious tasks, much like what you're doing now. But trying to make AppleScript do something outside of the very narrow range of things it's good for is just torturing yourself for no good reason.
ytk is offline   0 Reply With Quote
Old Jan 2, 2013, 03:01 PM   #13
moonman239
Thread Starter
macrumors 65816
 
Join Date: Mar 2009
Quote:
Originally Posted by ytk View Post
You don't have to do any of that. You can write the program in Ruby, Python, or Perl.
None of which I'm familiar with. I'm not much of a desktop programmer, anyway. I'm more of a Web & mobile app developer. In fact, as I stated, I'm working on a recipe app. I figure this little project may help me in the future, if not right now. I'd do the work myself, but doing the work by hand is boring. Building an app that will do the work for me is fun. And I can share the app with others so they don't have to do that work themselves. (Don't worry, guys, it'll be free of cost and maybe I'll put a GNU GPL on it.)
__________________
The funny thing about this signature is that by the time you get to the end of it, you will have spent between five and ten seconds doing so.
moonman239 is offline   0 Reply With Quote
Old Jan 2, 2013, 03:55 PM   #14
ytk
macrumors regular
 
Join Date: Jul 2010
No time like the present to learn. Any of those languages would be useful for a web developer, and Ruby can be used to write and deploy mobile apps for iOS. And like I said, if you'd started learning the language back when you first posted about the problem, you'd have it solved by now. Based on the problem you're describing, we're really only talking about maybe 10 lines of code here.

But go ahead and use AppleScript if you really want to. It's just not really well suited for this task. It's a bit like using a hammer to drive a screw—you can probably get it to work, but the result will be ugly, unreliable, and a pain to fix if something goes wrong.
ytk is offline   1 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
String and variable concatenation in AppleScript tekboi Mac Programming 6 Apr 15, 2014 02:37 PM
Applescript newb: declaring a variable in another script. Vanilla Face Mac Programming 2 Jan 5, 2014 08:39 PM
How to set environmental variable? hajime Mac Basics and Help 3 Sep 28, 2013 10:33 PM
How do I set the position of an element relative to another element? moonman239 Web Design and Development 3 Mar 3, 2013 05:30 PM
(AppleScript) "Tell"-ing every XML element to do something moonman239 Mac Programming 2 Jan 3, 2013 05:06 PM

Forum Jump

All times are GMT -5. The time now is 07:50 AM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC