Reading Property List data from a file

I’m trying to read a Property List from a data file as a proof-of-concept. The simple data file looks like:


// File:           test
// Creation Date:  11/23/2004
// Edited Date:    11/23/2004
// Description:    This is a test file
//
(Value1: 1, CalcOp: 1, Value2: 2)
(Value1: 3, CalcOp: 1, Value2: 7)
(Value1: 2, CalcOp: 1, Value2: 9)

The test script looks like:


open file "~/Desktop/test" for reading
Repeat with n=1 to the number of lines in file "~/Desktop/test"
	put line n of file "~/Desktop/test" into data
	if chars 1 to 2 of data <> "//" then      // Ignore comments
		put data into IconView_Icon
		put IconView_Icon
		Repeat with each item of keys(IconView_Icon)
			put it into PropName
			put property it of IconView_Icon into PropValue
			
			(*  Will be replacing PUT with TypeText  below:  *)
			put "The Property Name is: " & PropName
			put "The Property Value is: " & PropValue
			put " "
		end repeat
	end if
end repeat

The code just skips the second repeat where I’m trying to separate the property name from the value giving me a result of:


(Value1:1, CalcOp: 1, Value2:2)
...

instead of something like:


(Value1:1, CalcOp: 1, Value2:2)
The Property Name is: Value1
The Property Value is: 1
The Property Name is: CalcOp
The Property Value is: 1
The Property Name is: Value2
The Property Value is: 2
...

I’ve tried several variations with no luck. If I PUT a line of data in the script it works fine. I’ll continue to try but any help would be appreciated.

Happy Thanksgiving, Bruce :roll:

Hello Bruce,

You were very close. Here is a slightly modified version of your script that will do what you want:

Repeat with n=1 to the number of lines in file "~/Desktop/test"
	put line n of file "~/Desktop/test" into data 
	if chars 1 to 2 of data <> "//" then      // Ignore comments
		put value(data) into IconView_Icon 
		put IconView_Icon 
		Repeat with each item of keys(IconView_Icon) 
			put it into PropName 
			put property (it) of IconView_Icon into PropValue 
			
			(*? Will be replacing PUT with TypeText? below:? *) 
			put "The Property Name is: " & PropName 
			put "The Property Value is: " & PropValue 
			put " " 
		end repeat
	end if 
end repeat 

Let me explain the 3 changes I made, and then suggest another idea or two.

First, the key thing you were missing was the use of the value() function (in the 4th line of the script above). When the value is read from the file, it is stored in the “data” variable as a text string. The value() function evaluates this text as a SenseTalk expression, which in this case results in a property list value in place of its text representation.

Second, I put parentheses around “it” at line 8 (“put property (it) of IconView_Icon into PropValue”). Strictly speaking, in the current version of Eggplant this is not necessary. The way you wrote it (without parentheses) is perfectly correct right now. However, we expect this to change for the next release, as we move to correct the inconsistency that exists now between the syntax for accessing a property using the word “property” and the other ways of accessing a property (see the topic “Planned Property Syntax Change” in the “Looking Ahead” forum for a detailed explanation).

Using parentheses ensures that SenseTalk will treat (it) as an expression and therefore use the value of the it variable as the property name and not try to access a property named “it”, both now and in the future.

The third change I made was to delete the first line of your script, opening the test data file. Because the script accesses the data file by simply treating it as a container, it’s not necessary to open the file first. The open file command is only needed when your script will be doing sequential (or random) reading and updating of the file using the read, seek, or write commands. For most purposes it is simpler to ignore those commands and just access the file directly as you have done.

You could make your script even shorter (and avoid having to name the file twice), by changing the repeat loop from this:

Repeat with n=1 to the number of lines in file "~/Desktop/test"
	put line n of file "~/Desktop/test" into data 
	-- do stuff with data here
end repeat 

to this:

Repeat with data = each line of file "~/Desktop/test"
	-- do stuff with data here
end repeat 

Finally, here is an idea for a different way of structuring the data file. Instead of using SenseTalk’s property list format on each line of the data file, you could structure the file as a simple tab-delimited text file. The first line might hold the labels for each of the columns, with the data values on subsequent lines like this:

Value1  CalcOp  Value2
1       1       2
3       1       7
2       1       9

A script to read this data file might look like this:

put file "~/Desktop/test" into sourceData
put line 1 of sourceData into header -- get the first line
delete line 1 of sourceData
set the itemDelimiter to tab
Repeat with data = each line of sourceData
	set record to (:)
	repeat with n=1 to the number of items in header
		set property (item n of header) of record to item n of row
	end repeat
	insert record after recordList
end repeat 

At this point, recordList would contain a list of property lists, one for each line of data from the file, with the properties set using the names from the first line of the data file.

This isn’t necessarily a better approach, just different. It has the advantage of being a simpler and smaller data file. The original format you proposed, on the other hand, offers more flexibility, since the record defined on each line could have different sets of keys.

I hope this answer was helpful.

Doug

Many thanks Doug! I’ll give it a try in the morning but I already have confidence it will work well.

Todays demo to our project developers and management went well too. I had two simultanious Eggplant scripts and a QuickTime movie playing at the entry to clear out some of the Mac application capabilities. Although we still have our regular work que, we seem to be getting “go forth and conquer” support. :shock:

Think snow! Bruce

:smiley:
Doug, Matt, John, Jonathan, et. al.,

In my opinion, you guys write beautiful code! I think Doug read my mind when he figured I wanted to do an intelligent spreadsheet entry. I?m tired of trying to decipher regular comma delimited files and when I saw your Property List option I thought that looks good. One of our applications has a huge multi-tabbed, multi-screen spread sheet feel to it. Doug?s modification of my idea will hopefully make things cleaner yet.

Because I don?t have my work application at home, I?m learning Eggplant with the simple calculator that comes on most systems. My first milestone beyond basic control was the comparison of values between a test application and the independent test script. Matt gave me help with ?Using SetRemoteClipboard w/variable? to get me past that hump. My calculator script randomly selects 100 numbers between zero and nine, 50 operations, introduces a pseudo-error whenever the number five is selected, and gives notification of faults and percent accuracy upon completion. The piece of code Doug added will let me use specific numbers and operations that could be easily copied and edited for other tests without changing the script. I?ll try to submit the two for the ?Examples? page because I think they could help others. I?ve been stuck in a cave manually testing for the past few years and my education wasn?t Computer Science so they might look pretty primitive.

These two examples bring together a point on documentation though. I?ve seen a bit here and a bit there and bring them together. I?m not sure I ever would have found the ?value(data)? connection on my own. In some cases documentation on a function needs support from other lines in order for it to work. Example:
Eggplant Reference: SetRemoteClipboard ?The SetRemoteClipboard function puts the text you specify into the SUT clipboard.? It took me a while to figure I needed to add ?TypeCommand ?c?? before using it and ?put RemoteClipboard() into xxx? after in order for it to work.

This is where having more examples will help.

I am receiving encouragement to use a more conventional auto-script serial approach instead so I may be a bit slower in getting this out.

Hope to catch up with some of you at MacWorld/SF.

Soon, Bruce