I’ve written some code to parse a string-ified .plist file, and I thought someone somewhere might find this useful. Here’s the code:
-- plistParser
-- version 1.01
--
-- based on an XML parser by Roberto Ierusalimschy at:
-- lua-users.org/wiki/LuaXml
--
-- Takes a string-ified .plist file as input, and outputs
-- a table. Nested dictionaries and arrays are parsed into
-- subtables. Table structure will match the structure of
-- the .plist file
--
-- usage:
-- local plistStr = <string-ified plist file>
-- local plistTable = plistParse(plistStr)
--
local plp = {}
function plp.nextTag(s, i)
return string.find(s, "<(%/?)([%w:]+)(%/?)>", i)
end
function plp.array(s, i)
local arr, nextTag, array, dictionary = {}, plp.nextTag, plp.array, plp.dictionary
local ni, j, c, label, empty
while true do
ni, j, c, label, empty = nextTag(s, i)
assert(ni)
if c == "" then
if empty == "/" then
if label == "dict" or label == "array" then
arr[#arr+1] = {}
else
arr[#arr+1] = (label == "true") and true or false
end
elseif label == "array" then
arr[#arr+1], i, j = array(s, j+1)
elseif label == "dict" then
arr[#arr+1], i, j = dictionary(s, j+1)
else
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
local val = string.sub(s, i, ni-1)
if label == "integer" or label == "real" then
arr[#arr+1] = tonumber(val)
else
arr[#arr+1] = val
end
end
elseif c == "/" then
assert(label == "array")
return arr, j+1, j
end
i = j + 1
end
end
function plp.dictionary(s, i)
local dict, nextTag, array, dictionary = {}, plp.nextTag, plp.array, plp.dictionary
local ni, j, c, label, empty
while true do
ni, j, c, label, empty = nextTag(s, i)
assert(ni)
if c == "" then
if label == "key" then
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
assert(c == "/" and label == "key")
local key = string.sub(s, i, ni-1)
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
if empty == "/" then
if label == "dict" or label == "array" then
dict[key] = {}
else
dict[key] = (label == "true") and true or false
end
else
if label == "dict" then
dict[key], i, j = dictionary(s, j+1)
elseif label == "array" then
dict[key], i, j = array(s, j+1)
else
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
local val = string.sub(s, i, ni-1)
if label == "integer" or label == "real" then
dict[key] = tonumber(val)
else
dict[key] = val
end
end
end
end
elseif c == "/" then
assert(label == "dict")
return dict, j+1, j
end
i = j + 1
end
end
function plistParse(s)
local i, ni, tag, version, empty = 0
while label ~= "plist" do
ni, i, label, version = string.find(s, "<([%w:]+)(.-)>", i+1)
assert(ni)
end
ni, i, _, label, empty = plp.nextTag(s, i)
if empty == "/" then
return {}
elseif label == "dict" then
return plp.dictionary(s, i+1)
elseif label == "array" then
return plp.array(s, i+1)
end
end
I’ve put an example plist in my Dropbox public folder so I could post an example of how to use it. Here’s the example:
--Main
function setup()
http.request("https://dl.dropbox.com/u/8445683/test.plist", plistLoaded)
end
function plistLoaded(data, status, headers)
local plist = plistParse(data)
deepPrint(plist)
end
function deepPrint(t, prefix)
if prefix == nil then prefix = "" end
if not next(t) then print(prefix.."{empty}") return end
for k,v in pairs(t) do
if type(v) == "table" then
print(prefix.."["..tostring(k).."] -> table")
deepPrint(v, prefix .. " ")
else
print(prefix.."["..tostring(k).."]: "..tostring(v))
end
end
end
function draw()
background(0)
end
If you run into any bugs, let me know and I’ll try to fix them. Also, if you have any suggestions for improvement I’ll consider incorporating them.