Skip to content

Instantly share code, notes, and snippets.

@minoki
Created December 27, 2009 09:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save minoki/264219 to your computer and use it in GitHub Desktop.
Save minoki/264219 to your computer and use it in GitHub Desktop.
local assert,error,setmetatable,tonumber = assert,error,setmetatable,tonumber
local table = require "table"
local io = require "io"
local lxp = require "lxp"
local base64 = require "base64"
module "propertylist"
array_metatable = {}
dictionary_metatable = {}
local function callback_EndElement(p,name,attr)
local callbacks = p:getcallbacks()
assert(name == callbacks.current.tagname,"tag name mismatch: "..name.."<->"..callbacks.current.tagname)
local handler = callbacks.current.EndElement
callbacks.current = callbacks.current.parent
if handler then
handler()
end
end
local function callback_CharacterData(p,s)
local callbacks = p:getcallbacks()
if callbacks.current.CharacterData then
callbacks.current.CharacterData(s)
end
end
local function callback_StartElement(p,name,attr)
local callbacks = p:getcallbacks()
callbacks.current = {
tagname = name,
parent = callbacks.current,
currentDict = callbacks.current and callbacks.current.currentDict
}
if name == "plist" then
callbacks.current.valueHandler = function(a)
callbacks.root = a
end
elseif name == "key" then
local key = ""
callbacks.current.CharacterData = function(k)
key = k
end
local currentDict = callbacks.current.parent.currentDict
callbacks.current.EndElement = function()
callbacks.current.valueHandler = function(a)
currentDict[key] = a
end
end
elseif name == "true" then
callbacks.current.parent.valueHandler(true)
elseif name == "false" then
callbacks.current.parent.valueHandler(false)
elseif name == "real" or name == "integer" then
callbacks.current.CharacterData = function(x)
callbacks.current.parent.valueHandler(tonumber(x))
end
elseif name == "string" or name == "date" then
callbacks.current.CharacterData = function(x)
callbacks.current.parent.valueHandler(x)
end
elseif name == "data" then
callbacks.current.CharacterData = function(x)
callbacks.current.parent.valueHandler(base64.decode(x))
end
elseif name == "array" then
local t = {}
callbacks.current.valueHandler = function(a)
table.insert(t,a)
end
callbacks.current.EndElement = function()
callbacks.current.valueHandler(setmetatable(t,array_metatable))
end
elseif name == "dict" then
local currentDict = {}
callbacks.current.currentDict = currentDict
callbacks.current.EndElement = function()
callbacks.current.valueHandler(setmetatable(currentDict,dictionary_metatable))
end
else
error("unknown tag:"..name)
end
end
function parse(data)
local callbacks = {
StartElement = callback_StartElement,
CharacterData = callback_CharacterData,
EndElement = callback_EndElement,
current = nil,
root = nil
}
local parser = lxp.new(callbacks)
parser:parse(data)
parser:close()
return callbacks.root
end
function parsefile(filename)
local f = assert(io.open(filename))
local data = f:read("*a")
f:close()
return parse(data)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment