Adding a plist item with an unique name

I’m trying to make this work:

  • I need to add new items to a Plist file that already exists
  • First I want to check if a name exists if so adjust the name
  • add the item to the list (here it doesn’t work)


-- The item name consist of Testxxxx where the xxxx has to range between 4999 and smaller
set thePlistItemNameNumber to "4999" 
set thePlistItemName to "Test" & thePlistItemNameNumber

tell application "System Events"
	tell property list file "/Library/Preferences/com.myPListFile.plist"
		tell contents
			-- check if Test4999 exists end if so make another name
			if property list item thePlistItemName exists then
				set thePlistItemNameNumber to thePlistItemNameNumber - 1
				set thePlistItemName to "Test" & thePlistItemNameNumber
				repeat while property list item thePlistItemName exists
					set thePlistItemNameNumber to thePlistItemNameNumber - 1
					set thePlistItemName to "Test" & thePlistItemNameNumber
				end repeat
			end if
			-- here I trie to add the new item but it doesn't take the name Test4999 just displays "thePlistItemName"
			set previousValue to value
			set value to (previousValue & {|thePlistItemName|:"Test"})
		end tell
	end tell
end tell

display dialog thePlistItemName


Any ideas?

thx

Script has not set ‘value’.
And I suspect you cannot add a new key in this way.

the value refers to the contents of the plist file and it contains all the items that originally are in the plist file.

this part works, but it won’t add the variable stored in the thePlistItemName, but writes “thePlistItemName”

Here is a handler (or better two handlers) that I wrote a while ago. Maybe they are helpful to you. I think the second one is more correct, but I haven’t played around with them in a while. Both of them seem to work fine.

To test it, create a plist “test.plist” on your desktop with the following content:

Then run the following test-script. You should then have 4 new keys in your plist.


set pListPath to POSIX path of (path to desktop) & "test.plist"

-- using addKey
addKey(pListPath, "testKey2", "file2")
addKey(pListPath, "testKeyArray3", {"list3", 33})

-- using addKey2
addKey2(pListPath, "testKey4", "file4", text)
addKey2(pListPath, "testKeyArray5", {"list5", 55}, list)


-- -- -- -- -- -- HANDLERS

--c--   addKey(posixPath, keyname, keyValue)
--d--   Add property item to existing plist. Case of key name is preserved. 
--d--   Case is not preserved for subkeys in records unless properly piped.
--a--   posixPath : string -- posix path to plist
--a--   keyname : string -- name of new property
--a--   keyValue : anything
--r--    nothing
--x--   addKey(plistPath, "NewKey", {"ABC", 33}) --> new key in plist
--u --  ljr_nbg 
on addKey(posixPath, keyname, keyValue)
	local posixPath, keyname, keyValue
	local newStr, chars, lst, scpt, oldStr, ASTID
	set ASTID to AppleScript's text item delimiters
	try
		--escape backslashes and pipes in the identifier-to-be
		set keyname to keyname as string
		repeat with chars in {{"\\", "\\\\"}, {"|", "\\|"}}
			set {oldStr, newStr} to chars
			if oldStr is in keyname then
				set AppleScript's text item delimiters to oldStr
				set lst to keyname's text items
				set AppleScript's text item delimiters to newStr
				set keyname to lst as string
			end if
		end repeat
		set keyname to "|" & keyname & "|"
		set AppleScript's text item delimiters to ASTID
		set scpt to "script\r\ton fn(posixPath,keyValue)\r\t\ttell application " & ¬
			"\"System Events\"\r" & "\t\t\ttell property list file posixPath\r" & ¬
			"\t\t\t\ttell contents\r\t\t\t\t\tset previousValue to value\r\t\t" & ¬
			"\t\t\tset value to (previousValue & {" & keyname & ¬
			":keyValue})\r\t\t\t\tend tell\r\t\t\tend tell\r\t\tend tell\r\tend" & ¬
			" fn\t\rend script"
		fn(posixPath, keyValue) of (run script scpt)
	on error eMsg number eNum
		set AppleScript's text item delimiters to ASTID
		error "Can't addKey: " & eMsg number eNum
	end try
end addKey

--c--   addKey2(posixPath, keyname, keyValue, keyType)
--d--   Add property item to existing plist. Case of key name is preserved. 
--d--   Case of subkey names in records is also preserved.
--a--   posixPath : string -- posix path to plist
--a--   keyname : string -- name of new property
--a--   keyValue : anything
--a--   keyType : AppleScript class supported by plist
--r--    nothing
--x--   addKey2(plistPath, "NewKey", {"ABC", 33},list) --> new key in plist
--u --  ljr_nbg 
on addKey2(posixPath, keyname, keyValue, keyType)
	local posixPath, keyname, keyValue, plistFile
	local keyType
	try
		tell application "System Events"
			set plistFile to property list file posixPath
			make new property list item at end of property list items ¬
				of contents of plistFile with properties ¬
				{kind:keyType, name:keyname, value:keyValue}
		end tell
	on error eMsg number eNum
		error "Can't addKey2: " & eMsg number eNum
	end try
end addKey2

Hope this helps.

Cheers, Luke

thx man! you were right that did the trick

Might have cheered too soon :frowning:

Your handler adds new keys to the plist file but i still have two problems:

  1. when i change the type to number instead of text it still adds the key as string

  2. one of my values is a path to a directory that should be in the volumes:external drive:dir1:subdir2: format
    but it always ends up being written as /volumes/external drive/dir1/subdir2
    → i’ve tested and this format isn’t accepted by the application that uses the plist

Any help would be very appreciated!


set directoryPath to choose folder with prompt "Choose the folder:" default location the path to home folder
set pListPath to POSIX path of (path to desktop) & "test.plist"

addKey2(pListPath, "testKey4", "4", number)
addKey2(pListPath, "testKey5", directoryPath, string)

on addKey2(posixPath, keyname, keyValue, keyType)
	local posixPath, keyname, keyValue, plistFile
	local keyType
	try
		tell application "System Events"
			set plistFile to property list file posixPath
			make new property list item at end of property list items ¬
				of contents of plistFile with properties ¬
				{kind:keyType, name:keyname, value:keyValue}
		end tell
	on error eMsg number eNum
		error "Can't addKey2: " & eMsg number eNum
	end try
end addKey2


Hey Bramster,

remove the quotes from your integer or coerce! Try this:


addKey2(pListPath, "testKey4", "5", number) --> addes as string since you provide a string
addKey2(pListPath, "testKey5", "5" as integer, number) --> added as integer (string coerced to integer)
addKey2(pListPath, "testKey6", 5, number) --> added as integer since that what is already is

As to your second question:

Aliases are converted to posix paths automatically.
If you really want to preserve Mac-like paths, try this:

set pListPath to POSIX path of (path to desktop) & "test.plist"

set pListAlias to POSIX file pListPath as alias --> now it is an alias 
set pListAliasString to pListAlias as string --> now it is a string

addKey2(pListPath, "testKey9", pListAliasString, text) --> Mac-like path in plist

Note that you will always have to coerce it to an alias when reading it back in. So it doesn’t actually matter whether you have a Mac-like or a posix path:


posix file "/Users/yourName/Desktop/test.plist" as alias --> an alias
"Mac:Users:yourName:Desktop:test.plist" as alias --> an alias

You see?

And now keep cheering (I hope :wink: )

Thx offcourse! --stupid mistake–

Any idea for the other problem perhaps?

-B.

And since I was talking about reading keys back in, I should give you this handler:

--c--   readKey(posixPath, keyname)
--d--   Read value of existing key in existing plist.
--a--   posixPath : string -- posix path to plist
--a--   keyname : string -- name of property (case-sensitive)
--r--    anything -- value of key
--x--   readKey(thePListPath, "User Email") --> value of key in plist
--u --  ljr_nbg 
on readKey(posixPath, keyname)
	local posixPath, keyname, val
	try
		tell application "System Events"
			tell property list file posixPath
				tell contents
					set val to value of property list item keyname
				end tell
			end tell
		end tell
		return val
	on error eMsg number eNum
		error "Can't readKey: " & eMsg number eNum
	end try
end readKey

Hope this helps!

(Info: I edited post #7 to answer your second question)

works like a charm now

thx ljr_nbg

You’re welcome.

Glad you got it working :wink: