Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

moonman239

Cancelled
Original poster
Mar 27, 2009
1,541
32
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.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,706
8,346
A sea of green
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?
 

ytk

macrumors 6502
Jul 8, 2010
252
5
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. :rolleyes:
 

moonman239

Cancelled
Original poster
Mar 27, 2009
1,541
32
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.

----------

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. :rolleyes:

I kind of like using AppleScript for things like this.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,706
8,346
A sea of green
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.
 

moonman239

Cancelled
Original poster
Mar 27, 2009
1,541
32
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.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,706
8,346
A sea of green
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
 

moonman239

Cancelled
Original poster
Mar 27, 2009
1,541
32
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.
 

moonman239

Cancelled
Original poster
Mar 27, 2009
1,541
32
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.
 

moonman239

Cancelled
Original poster
Mar 27, 2009
1,541
32
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! :p

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.
 

ytk

macrumors 6502
Jul 8, 2010
252
5
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.
 

moonman239

Cancelled
Original poster
Mar 27, 2009
1,541
32
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.)
 

ytk

macrumors 6502
Jul 8, 2010
252
5
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. :D 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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.