Mac How to read plist value by AppleScript?

mikezang

macrumors 6502a
Original poster
May 22, 2010
772
1
Tokyo, Japan
I have a plist file as below, I want to get all value of "showName" and "videoURLString", how can I read it by AppleScript or bash easily? especially when there a lot of "dict" in plist file.

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
* <dict>
* * <key>showName</key>
* * <string>* ** ** ** *</string>
* * <key>subIndex</key>
* * <string>0</string>
* * <key>typeID</key>
* * <string>1</string>
* * <key>vid</key>
* * <string>15669746</string>
* * <key>videoURLString</key>
* * <string>http://ip/file.txt</string>
* </dict>
</array>
</plist>
 

mikezang

macrumors 6502a
Original poster
May 22, 2010
772
1
Tokyo, Japan
I tried code as below, but I got error, what can I do?
Code:
defaults read ~/Downloads.plist "showName"
The error message is as below:
Preference plist for {~/Downloads.plist : kCFPreferencesCurrentUser : kCFPreferencesAnyHost} was not a dictionary.
2012-08-26 00:36:42.168 defaults[8969:707]
The domain/default pair of (~Downloads.plist, showName) does not exist
 

kryten2

macrumors 6502a
Mar 17, 2012
996
59
Belgium
I got the same error when using your plist. Perhaps it has a syntax error. When using PlistBuddy like chown33 said I get this :

@chown33

Thanks for the PlistBuddy tip.

Edit after changing the plist to :

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>showName</key>
<string>* ** ** ** *</string>
<key>subIndex</key>
<string>0</string>
<key>typeID</key>
<string>1</string>
<key>vid</key>
<string>15669746</string>
<key>videoURLString</key>
<string>http://ip/file.txt</string>
</dict>
</plist>
The result is the second tumbnail.
 

Attachments

Last edited:

mikezang

macrumors 6502a
Original poster
May 22, 2010
772
1
Tokyo, Japan
I got the same error when using your plist. Perhaps it has a syntax error. When using PlistBuddy like chown33 said I get this :

@chown33

Thanks for the PlistBuddy tip.

Edit after changing the plist to :

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>showName</key>
<string>* ** ** ** *</string>
<key>subIndex</key>
<string>0</string>
<key>typeID</key>
<string>1</string>
<key>vid</key>
<string>15669746</string>
<key>videoURLString</key>
<string>http://ip/file.txt</string>
</dict>
</plist>
The result is the second tumbnail.
You can't remove Array tag, that is what I have to parse element.

----------

If you are using AppleScriptObjC, you can also use NSArray's valueForKey: method, via either a Cocoa-AppleScript application or ASObjC Runner.
I am not sure whyit Is so difficult to parse plist with array? it is so popular to be used in plist file....
 
Last edited:

Red Menace

macrumors 6502
May 29, 2011
396
55
Littleton, Colorado, USA
I am not sure whyit Is so difficult to parse plist with array? it is so popular to be used in plist file....
It isn't all that difficult, I suppose it depends on exactly what you are doing and what you mean by "easily". Using System Events, you can loop through the dictionaries in the array (a general-purpose handler to get an individual item is about 18 lines of code), while using ASObjC Runner the statements can be simplified to one, and it takes a couple of statements using Cocoa methods to get all the values for a particular key.
 

mikezang

macrumors 6502a
Original poster
May 22, 2010
772
1
Tokyo, Japan
It isn't all that difficult, I suppose it depends on exactly what you are doing and what you mean by "easily". Using System Events, you can loop through the dictionaries in the array (a general-purpose handler to get an individual item is about 18 lines of code), while using ASObjC Runner the statements can be simplified to one, and it takes a couple of statements using Cocoa methods to get all the values for a particular key.
Can you show me that 18 lines code?
By the way, for AsObjC Runner, I have to install a application, so I thought 18 is better than 1:)
 

Red Menace

macrumors 6502
May 29, 2011
396
55
Littleton, Colorado, USA
The following example uses a general-purpose handler that takes a list of items to define an element to get a value from:


Code:
on run -- example
	set plistFile to (choose file) -- the plist file to use
	set theKeys to {"showName", "videoURLString"} -- the keys to get values of
	
	set X to 1 -- begin with the first array item
	set theResult to {} -- this will be the values of the keys of the array items
	repeat -- forever, or at least until there is an error in getting an element
		try -- group the results - in this example, a list of lists of the key values
			set keyItems to {} -- this will be the values of the keys in the current array item
			repeat with aKey in theKeys
				set end of keyItems to (getPlistElement from {plistFile, X, aKey})
			end repeat
			set end of theResult to keyItems
		on error errmess
			log errmess
			exit repeat
		end try
		set X to X + 1 -- the next array item
	end repeat
	
	return theResult
end run


to getPlistElement from plistItems
	(*
	get the specified element from a simple plist structure by name or index
    	the number of items is not fixed, but must be at least 2 (the Plist file and a Plist element)
 		parameters:		plistItems [list] -
							item 1 [varies]: the plist file path
							item 2 [varies]: the plist element name or index (names are case sensitive)
							item(s) 3+ [varies]: sub item(s)
		returns [mixed]:	contents of the element
	*)
	try
		if (count plistItems) is less than 2 then error "getPlistElement handler:  item list contains too few items"
		tell application "System Events"
			set thePlistElement to property list file ((first item of plistItems) as text) -- start at the root element
			
			repeat with anItem in rest of plistItems -- add on the sub items
				set anItem to the contents of anItem
				set thePlistElement to (get property list item anItem of thePlistElement)
			end repeat
			
			return value of thePlistElement
		end tell
	on error errorMessage number errorNumber
		log errorMessage
		error "getPlistElement handler:  element not found (" & errorNumber & ")"
	end try
end getPlistElement
 

mikezang

macrumors 6502a
Original poster
May 22, 2010
772
1
Tokyo, Japan
Hi, can you show me a sample? I tried code as below, but with error message:
"Print: Entry, "dict:0:showName", Does Not Exist"

Code:
/usr/libexec/PlistBuddy -c "Print dict:0:showName" "${downloadsplistfile}"
Well, I just got it with code as below by myself. anyway, thanks for you to tell me PlistBuddy:)
Code:
plistfile="${HOME}/Downloads.plist"

showName="$(/usr/libexec/PlistBuddy -c "Print" "${plistfile}" | awk '/showName = /{print $3}' | nl)"
videoURLString="$(/usr/libexec/PlistBuddy -c "Print" "${plistfile}" | awk '/videoURLString = /{print $3}' | nl)"

printf "%s\n" "${showName[@]}"
printf "%s\n" "${videoURLString[@]}"