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*%s*$") then local cdata = value:match("") 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 }