235 lines
7.6 KiB
Lua
235 lines
7.6 KiB
Lua
local errorManager = require("errorManager")
|
|
local log = require("log")
|
|
local XMLNode = {
|
|
new = function(tag)
|
|
return {
|
|
tag = tag,
|
|
value = nil,
|
|
attributes = {},
|
|
children = {},
|
|
|
|
addChild = function(self, child)
|
|
table.insert(self.children, child)
|
|
end,
|
|
|
|
addAttribute = function(self, tag, value)
|
|
self.attributes[tag] = value
|
|
end
|
|
}
|
|
end
|
|
}
|
|
|
|
local parseAttributes = function(node, s)
|
|
local _, _ = string.gsub(s, "(%w+)=([\"'])(.-)%2", function(attribute, _, value)
|
|
node:addAttribute(attribute, "\"" .. value .. "\"")
|
|
end)
|
|
local _, _ = string.gsub(s, "(%w+)={(.-)}", function(attribute, expression)
|
|
node:addAttribute(attribute, expression)
|
|
end)
|
|
end
|
|
|
|
local XMLParser = {
|
|
parseText = function(xmlText)
|
|
local stack = {}
|
|
local top = XMLNode.new()
|
|
table.insert(stack, top)
|
|
local ni, c, label, xarg, empty
|
|
local i, j = 1, 1
|
|
while true do
|
|
ni, j, c, label, xarg, empty = string.find(xmlText, "<(%/?)([%w_:]+)(.-)(%/?)>", i)
|
|
if not ni then break end
|
|
local text = string.sub(xmlText, i, ni - 1);
|
|
if not string.find(text, "^%s*$") then
|
|
local lVal = (top.value or "") .. text
|
|
stack[#stack].value = lVal
|
|
end
|
|
if empty == "/" then
|
|
local lNode = XMLNode.new(label)
|
|
parseAttributes(lNode, xarg)
|
|
top:addChild(lNode)
|
|
elseif c == "" then
|
|
local lNode = XMLNode.new(label)
|
|
parseAttributes(lNode, xarg)
|
|
table.insert(stack, lNode)
|
|
top = lNode
|
|
else
|
|
local toclose = table.remove(stack)
|
|
|
|
top = stack[#stack]
|
|
if #stack < 1 then
|
|
errorManager.error("XMLParser: nothing to close with " .. label)
|
|
end
|
|
if toclose.tag ~= label then
|
|
errorManager.error("XMLParser: trying to close " .. toclose.tag .. " with " .. label)
|
|
end
|
|
top:addChild(toclose)
|
|
end
|
|
i = j + 1
|
|
end
|
|
local text = string.sub(xmlText, i);
|
|
if #stack > 1 then
|
|
error("XMLParser: unclosed " .. stack[#stack].tag)
|
|
end
|
|
return top.children
|
|
end
|
|
}
|
|
|
|
local log = require("log").debug
|
|
|
|
local function convertValue(value, scope)
|
|
if value:sub(1,1) == "\"" and value:sub(-1) == "\"" then
|
|
value = value:sub(2, -2)
|
|
end
|
|
|
|
if value:sub(1,2) == "${" and value:sub(-1) == "}" then
|
|
value = value:sub(3, -2)
|
|
if(scope[value])then
|
|
return scope[value]
|
|
else
|
|
errorManager.error("XMLParser: variable '" .. value .. "' not found in scope")
|
|
end
|
|
end
|
|
|
|
if value:match("^%s*<!%[CDATA%[.*%]%]>%s*$") then
|
|
local cdata = value:match("<!%[CDATA%[(.*)%]%]>")
|
|
local env = _ENV
|
|
for k,v in pairs(scope) do
|
|
env[k] = v
|
|
end
|
|
return load("return " .. cdata, nil, "bt", env)()
|
|
end
|
|
|
|
if value == "true" then
|
|
return true
|
|
elseif value == "false" then
|
|
return false
|
|
elseif colors[value] then
|
|
return colors[value]
|
|
elseif tonumber(value) then
|
|
return tonumber(value)
|
|
else
|
|
return value
|
|
end
|
|
end
|
|
|
|
local function createTableFromNode(node, scope)
|
|
local list = {}
|
|
|
|
for _, child in pairs(node.children) do
|
|
if child.tag == "item" or child.tag == "entry" then
|
|
local item = {}
|
|
|
|
for attrName, attrValue in pairs(child.attributes) do
|
|
item[attrName] = convertValue(attrValue, scope)
|
|
end
|
|
|
|
for _, subChild in pairs(child.children) do
|
|
if subChild.value then
|
|
item[subChild.tag] = convertValue(subChild.value, scope)
|
|
elseif #subChild.children > 0 then
|
|
item[subChild.tag] = createTableFromNode(subChild)
|
|
end
|
|
end
|
|
|
|
table.insert(list, item)
|
|
else
|
|
if child.value then
|
|
list[child.tag] = convertValue(child.value, scope)
|
|
elseif #child.children > 0 then
|
|
list[child.tag] = createTableFromNode(child)
|
|
end
|
|
end
|
|
end
|
|
|
|
return list
|
|
end
|
|
|
|
local Container = {}
|
|
function Container:loadXML(content, scope)
|
|
scope = scope or {}
|
|
local nodes = XMLParser.parseText(content)
|
|
self:fromXML(nodes, scope)
|
|
end
|
|
|
|
local baseFromXml
|
|
function Container.setup()
|
|
baseFromXml = require("elementManager").getElement("BaseElement").fromXML
|
|
end
|
|
|
|
function Container:fromXML(content, scope)
|
|
baseFromXml(self, content, scope)
|
|
for _, node in ipairs(content) do
|
|
local capitalizedName = node.tag:sub(1,1):upper() .. node.tag:sub(2)
|
|
if self["add"..capitalizedName] then
|
|
local element = self["add"..capitalizedName](self)
|
|
element:fromXML(node, scope)
|
|
end
|
|
end
|
|
end
|
|
|
|
local BaseElement = {}
|
|
function BaseElement:fromXML(node, scope)
|
|
if(node.attributes)then
|
|
for k, v in pairs(node.attributes) do
|
|
if(self._properties[k])then
|
|
self.set(k, convertValue(v, scope))
|
|
elseif self[k] then
|
|
if(k:sub(1,2)=="on")then
|
|
local val = v:gsub("\"", "")
|
|
if(scope[val])then
|
|
self[k](self, scope[val])
|
|
else
|
|
errorManager.error("XMLParser: variable '" .. v .. "' not found in scope")
|
|
end
|
|
else
|
|
errorManager.error("XMLParser: property '" .. k .. "' not found in element '" .. self:getType() .. "'")
|
|
end
|
|
else
|
|
errorManager.error("XMLParser: property '" .. k .. "' not found in element '" .. self:getType() .. "'")
|
|
end
|
|
end
|
|
end
|
|
|
|
if(node.children)then
|
|
for _, child in pairs(node.children) do
|
|
if(self._properties[child.tag])then
|
|
if(self._properties[child.tag].type == "table")then
|
|
self.set(child.tag, createTableFromNode(child, scope))
|
|
else
|
|
self.set(child.tag, convertValue(child.value, scope))
|
|
end
|
|
else
|
|
local args = {}
|
|
if(child.children)then
|
|
for _, child in pairs(child.children) do
|
|
if(child.tag == "param")then
|
|
table.insert(args, convertValue(child.value, scope))
|
|
elseif (child.tag == "table")then
|
|
table.insert(args, createTableFromNode(child, scope))
|
|
else
|
|
errorManager.error("XMLParser: unknown child '" .. child.tag .. "' in element '" .. self:getType() .. "'")
|
|
end
|
|
end
|
|
end
|
|
|
|
if(self[child.tag])then
|
|
if(#args > 0)then
|
|
self[child.tag](self, table.unpack(args))
|
|
elseif(child.value)then
|
|
self[child.tag](self, convertValue(child.value, scope))
|
|
else
|
|
self[child.tag](self)
|
|
end
|
|
else
|
|
errorManager.error("XMLParser: method '" .. child.tag .. "' not found in element '" .. self:getType() .. "'")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return {
|
|
API = XMLParser,
|
|
Container = Container,
|
|
BaseElement = BaseElement
|
|
} |