how do you build a propety list with labels from a string?

Hello scripters,

I’m just stumped by this.

I have a list of strings where every odd entry in the list is a label and every even item is the contents of the field…i.e.

{“name”, “Fred”,“city”,“Seattle”,“hair-color”,“brown”}

and I want to convert it to a labelled property list, i.e.

{name:“Fred”,city:“Seattle”,hair-color:"brown}

yet I can’t seem to make it work.

If i try

set new_list to {(item 1 of old_list) & “:” &item 2 of old_list)}

I get

{“name:Fred”,“City:Seattle”,“hair-color:brown”}

My question: how do I coerce the first string to a label, rather than have it appear as a string?

Thanks for any and all suggestions!

best,
Eric

Don’t know if this is what you’re looking for but it displays “Seattle” for me:

set lst to {"name", "Fred", "city", "Seattle", "hair_color", "brown"}
set s to "{"
repeat with i from 1 to count of lst by 2
	set s to s & item i of lst & ":"" & item (i + 1) of lst & "","
end repeat
set rec to (text 1 through ((length of s) - 1) of s) & "}"
set theRec to run script rec
display dialog city of theRec

  • Dan

Using the RecordTools osax:

set lst to {"name", "Fred", "city", "Seattle", "hair-color", "brown"}
set rec to {}
repeat with i from 1 to count lst by 2
	set rec to set user property lst's item i to lst's item (i + 1) in rec
end repeat
rec --> {|name|:"Fred", city:"Seattle", |hair-color|:"brown"}

BTW, depending on what you’re doing you may prefer to store your data in some sort of associative list. Unfortunately, unlike most languages, AppleScript doesn’t have a built-in associative list/hash/dictionary type, but you can find a decent vanilla implementation in the Types library at AppleMods. Example:

-- boilerplate library-loading code

property _Loader : run application "LoaderServer"

----------------------------------------------------------------------
-- DEPENDENCIES

property _Types : missing value

on __load__(loader)
	set _Types to loader's loadLib("Types")
end __load__

----------------------------------------------------------------------

__load__(_Loader's makeLoader())

-- main code
set lst to {"name", "Fred", "city", "Seattle", "hair-color", "brown"}
set dct to _Types's makeDict()
repeat with i from 1 to count lst by 2
	dct's setItem(lst's item i, lst's item (i + 1))
end repeat
dct's getItem("name") --> "Fred"
dct's getItem("city") --> "Seattle"
dct's getItem("hair-color") --> "brown"

If you’ve not used AppleMods’ libraries before, you’ll need to download and install AppleMods’ Loader system first. Run the Loader installer, then download and add the Types library to the ASLibraries folder. You can use the LoaderWizard applet to generate boilerplate library-loading code to paste at the top of your scripts.

Thank you all for all the help. I think i’m a lot farther with this now!

I plugged dant’s suggestion into my program (I’m trying to do this with pure applescript, no osaxen), and it seems to build the string properly, but chokes when it hits the "run script " command, which I take interprets the string into a real list.

I think I’m getting that error because I’m in a tell loop to another program. Is there some way to preface or tag the runscript command so that I don’t have to restructure the tell loop? I tried sticking “my” in varioius places, but I obviously don’t understand what I’m doing. How do you get AS to interpret the string and send the variable back to itself?

Thanks again!

Eric

:stuck_out_tongue:

Never mind!

I see what I was doing wrong…

I didn’t realize some of my labels (which I’m pulling from html tags) had periods in them. Apparently applescript can’t handle a label with a period (why not? arrrgh!). That was causing the runscript to fail.

Just for the sake of understanding, is it possible to stuff periods in labels? If so how do you call them

i.e.

set x to my “dc.description” of x

doesn’t seem to work…

I can of course pull out the periods from my labels, but y’know, I’m trying to understand all this wacky coercion

best (and thanks!!!)

Eric

AppleScript identifiers can contain only alphanumeric and underscore characters (e.g. ‘foo_bar’) unless they begin and end with vertical bars, in which case any MacRoman character may be used (e.g. ‘|foo bar|’). See the ASLG for details.

BTW, are you sure a record is really what you want? Records are property lists whose structures are defined at compile-time, so unless you have to use them here (e.g. because you’re passing this data to an osax or application command that requires a record), then a dynamic, associative list-style structure is generally best. In Perl, Python, etc. you get built-in hash/dict types, e.g. (Python):

d = {"name":"Fred", "city":"Seattle", "hair-color":"brown"}
print d["city"] #--> "Seattle"

Sounds like that’s the sort of structure you really want. In AS you have to write your own or use a third-party implementation, which is slower (since it’s vanilla AS) but does the same job.

What you’re doing is code generation, and has nothing to do with coercion.

Anyway… dant’s code has several bugs - code generation is hackish and tricky to do well, which is why you should only use it as a last resort - so if you really have to build records using just vanilla AS then my Record library is about as robust as you’re likely to get:

_Record's listToRec({{"name", "Fred"}, {"city", "Seattle"}, {"hair-color", "brown"}})
--> {|name|:"Fred", city:"Seattle", |hair-color|:"brown"}

Just curious what they are - I’m trying to learn here too… :wink:

  • Dan
  • An out-of-range error occurs if lst is {}

  • String-to-identifier conversion is naive and unsafe (there’s no ideal way to do this, mind, but there are safer, more robust options)

  • Creating property values is unreliable and unsafe (naively assumes all values will be strings, will fail if value contains quotes)

The last two are also potential security holes that could allow malicious data to be passed in and executed as code (this is always a concern with code generation).

If you’re interested, compare with my Record library to see how it solves these problems. It isn’t perfect, as input checking is a bit weak and not as foolproof as it could be - try passing a flat list, e.g. _Record’s listToRec({“name”, “Fred”, “city”, “Seattle”}) - for amusing results. Plus it’s still a hack (as the documentation makes clear) so there’s all sorts of unanticipated/hard-to-prevent problems that might occur (e.g. what will happen if a string containing non-MacRoman characters is used as a label?).

Like I say; not an easy problem, and impossible to solve 100%. Even the osax-based alternative has issues (e.g. data copying). Best used only as a last resort when an associative list or other structure isn’t appropriate.

HTH

Thanks - regarding lst={}, non-strings, quotes in strings and so on, of course I wasn’t presenting this as a vetted script to handle all cases, just as an illustration of a list-to-record conversion. It seems your real argument is the use of run script which I certainly defer to - your points are well taken.

  • Dan

Yep, the basic principle - code generation using ‘run script’ to compile on the fly - is exactly the same. It’s nailing down all the caveats before one person’s proof-of-concept ends up as another’s finished production code that’s the tricky part. Cheers :wink: