Working With(out) Plist Files

Plist files are an attack on civility. Let’s use Python to convert them to a JSON formatted file for easier data handling. We’ll explore using the Plistlib.py and SimpleJson libraries, badmouth XML a little, show some code, and have a rollicking good time.
For the occasion I’ve created plist2json.py, a command line script that converts a PLIST file to a JSON file, and vice versa.


ยป Download Plist2json.py, v0.1 -- updated 02.09.08


Basic usage:

converts input file, outputs file:
$ plist2json -i myfile.plist -o myfile.json
$ plist2json -i myfile.json -o myfile.plist
converts input file, output to screen:
$ plist2json -i myfile.plist
converts to json, with pretty indenting:
$ plist2json -i myfile.plist -p
print out help and usage:
$ plist2json --help


And just when I thought XML couldn't get any uglier.

I'm not saying it doesn't have a place in this world (though it might be in the middle of the Atlantic)-- I think in every young man's journey down the path of computer righteousness, one of his first tasks is figuring out how to set up a web page. A small but meaningful step that introduces the concept of data and markup. Or to separate that which is said, and how thy should say it. We are helped along by our new companion HTML which introduces some strange words surrounded by a couple of funny looking brackets `<>`. Easy to read, easy to write, maybe a tad wordy-- but don't mess with with easy. I guess this is why XML took off, people love HTML right? -- why not use it for everything! System files, documents, transport, we'll bathe in it, maybe one day we'll speak it to our friends and family. Sure it's verbose, sure it's hard to read, sure it's hard to figure out intent after a couple of nestings, but damnit I told you not to mess with easy!

Now I make it a point to isolate myself from the Mac populace as much as possible. I love the operating system but most Mac people don't have much to say about it other than they like the blue background and they call me a PC guy even though I use the same programs they do. Fair enough, the price to pay for an easy to use system is users who want the system to be easy to use. I would happily leave them be but some of them are starting to leave their little dirty tendencies across the Internet.

Take for instance the "plist"-- what is this thing? Some kind of Apple configuration file that looks like XML but acts like a dictionary (in Python speak) with a key and associated value. That's all well and good but this monstrosity is an assault on legibility and common decency:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
--snip--
<key>defaultWidth</key>
<integer>500</integer>
<key>descender</key>
<integer>-282</integer>
<key>designer</key>
<string>Max Miedinger</string>
<key>fondID</key>
<integer>128</integer>
<key>fontStyle</key>
<integer>64</integer>
<key>xHeight</key>
<integer>524</integer>
<key>slantAngle</key>
<real>0.0</real>
--snip--

So not only does it hurt my eyes to read, but it’s not immediately apparent how I’m supposed to extract a value from a given key. Maybe I could swallow something that looked like <myKey type=string>”my value”</myKey> but the plist format is neither here nor there, a chimera of ugly and burdensome.

Meet my new friend, his name is Json.

JSON is one of those acronyms I’ve seen bantered about but didn’t know what the hell it did until I started googling for alternatives to XML. In a nutshell it’s a way to serialize data without all the crud in the plist file. I won’t go as far to say it’s a true alternative to XML, but if you are looking for an efficient way to get data from one program to the next — over the network or local, it’s hard to beat the syntax:

1
2
3
4
5
6
7
8
9
--snip--
"defaultWidth": 500,
descender": -282,
"designer": "Max Miedinger",
"fondID": 128,
"fontStyle": 64,
"xHeight": 524,
"slantAngle": 0.0,
--snip--

It doesn’t get much clearer than that. It’s quite apparent what value goes with what key, it’s just a matter of reading the list into a dict and accessing the individual element.

Getting from here to there.

Using a couple of lovely Python libraries we can tame the plist beast by converting it to a native dict to work on locally, then encode it in JSON format to send out into the world to easily mingle with more accommodating friends.
You’ll need to grab plistlib.py (or find it floating around the net, I think it’s part of Mac OSX), and throw it in with your Site-packages or just include it in your projects Python path. Give the code a quick look over, it’s got a few functions tucked away in there that are of good use to us, notably “readPlist()” and “writePlist()”.

1
2
3
4
import plistlibfp = open("myFile.plist", "r")
myDict = plistlib.readPlist(fp)
print myDict
print myDict["myKey"]

Very nice, now this is data we can work with. Do with it what you’d like and let’s repack it in a JSON format so we can use it somewhere else and leave the blasted plist format behind. You’ll need to install the quite awesome SimpleJson library [need a w32 compiled egg?].

1
2
import simplejsonmyString = simplejson.dumps(myDict)
print myString

And it just keeps getting easier. Now that we have a json string we can send it anywhere we want. Since there are encoders/decoders for nearly every language out there it’s trivial to read the data structure into a native format, just check json.org for some of the implementations.

You can always go home again.

I wrote a standalone script to convert a PLIST file to a JSON file, or back the other way if you want. You can download plist2json.py and check it out (see top of page for usage info), but don’t let the name fool you — it goes both ways, I just thought plist2json2plistAgain sounded a little funny. Nothing really earth shattering in it so I’ll show you the two functions of particular interest which does the actual conversion:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def plist2json(file, indent=False):
"""Read a PLIST file, return a JSON formatted string."""
import sys, plistlib, simplejson
try:
    inFile = open(file, "r")
    plDict = plistlib.readPlist(inFile)
    inFile.close()
except:
    sys.stderr.write("error reading plist file.")
    sys.exit(1)
try:
    if indent == True:
        pretty = 4 #space to indent
    else:
        pretty = None
        jsonStr = simplejson.dumps(plDict, indent=pretty)
except:
    sys.stderr.write("error converting dic to json.")
return jsonStr
 
def json2plist(file):
"""Read a JSON file, return a PLIST formatted string."""
import sys, cStringIO
import plistlib, simplejson
try:
    inFile = open(file, "r")
    jsonDic = simplejson.load(inFile)
    inFile.close()
except:
    sys.stderr.write("error reading json file.")
    sys.exit(1)
try:
    plistIO = cStringIO.StringIO()
    plistlib.writePlist(jsonDic, plistIO)
    plistStr = plistIO.getvalue()
    plistIO.close()
except:
    sys.stderr.write("error converting dic to plist.")
    sys.exit(1)
return plistStr

Hope that’s useful. I had a good time working with JSON and will no doubt use it with future projects. Legible and easy to work with, it’s hard to ask more out of a data-interchange format. Maybe there is hope for the future, mankind shall abandon XML and communicate with each other in JSON — I can’t imagine the speeches will stir the souls of men, but at least they will be easily parseable.

Posted on February 8, 2008

Tags: , , ,

Leave a comment