local global = _G; local lxp = lxp; local io = io; local table = table; local pairs = pairs; local assert = assert; local type = type; local setmetatable = setmetatable; local string = string; local error = error; local tonumber = tonumber; local print = print; -- DEBUGGING module(...) Node = { }; Node.__index = Node; -- create a new node function Node.create(_name, _attributes) local tmp = {}; setmetatable(tmp, Node); tmp._NAME = _name; tmp._ATTRIBUTES = _attributes; return tmp; end -- get a single element by it's name or index function Node:getElement(index) if( type(index) == "string" ) then for i,v in pairs(self) do if( v._NAME == index and i ~= "_ATTRIBUTES" ) then return v; end end return nil; -- not found end if( type(index) == "number" ) then if( index < 1 ) then return nil; end; -- invalid index if( index > #self ) then return nil; end; -- invalid index (not 100% accurate, but quick) local count = 0; for i,v in pairs(self) do if( type(v) == "table" and i ~= "_ATTRIBUTES" ) then count = count + 1; if( count == index ) then return v; end end end return nil; -- not found end return nil; -- invalid index type, return nil end -- get all elements as a table function Node:getElements() local tmp = {}; for i,v in pairs(self) do if( type(v) == "table" and i ~= "_ATTRIBUTES" ) then table.insert(tmp, v); end end return tmp; end -- get the number of elements that are a child of this node function Node:getElementCount() local count = 0; for i,v in pairs(self) do if( type(v) == "table" ) then count = count + 1; end end return count; end function Node:getAttribute(index) if( type(index) == "string" or type(index) == "number") then return self._ATTRIBUTES[index]; end return nil; end function Node:getAttributes() return self._ATTRIBUTES; end function Node:getAttributeCount() return #self._ATTRIBUTES; end -- return _NAME function Node:getName() return self._NAME; end -- return _VALUE function Node:getValue() return self._VALUE; end -- print a debug string of the current node function Node:debug() local str = string.format("Element \'%s\'", self._NAME); print(str); for i,v in pairs(self) do str = string.format(" %s:", i); print(str, v) end str = string.format("\n%s._ATTRIBUTES:", self._NAME); print(str); for i,v in pairs(self._ATTRIBUTES) do str = string.format(" %s:", i); print(str, v); end end function implicitCast(data) if( data == "true" ) then return true; end; if( data == "false" ) then return false; end; if( string.find(data, "[^%.?0-9+]") == nil ) then return tonumber(data); end -- convert hex string to number. if( string.find(data, "^(0x%x+)$") ~= nil) then --print ("data: ", data) return tonumber(data:sub(3), 16); end return data; end function startElement(parser, _name, _attributes) local stack = parser:getcallbacks().stack; for i,v in pairs(_attributes) do _attributes[i] = implicitCast(_attributes[i]); end local newtab = Node.create(_name, _attributes); table.insert(stack, newtab); end function endElement(parser, _name) local stack = parser:getcallbacks().stack; local element = table.remove(stack); local level = table.getn(stack); table.insert(stack[level], element); end function characterData(parser, str) if( not string.find(str, "%w") ) then return; end str = implicitCast(str); local stack = parser:getcallbacks().stack; local element = stack[table.getn(stack)]; local n = table.getn(element); if( element._VALUE ) then element._VALUE = element._value .. str; else element._VALUE = str; end end function open(filename) callbacks = { StartElement = startElement, EndElement = endElement, CharacterData = characterData, _nonstrict = true, stack = {{}}} local p = lxp.new(callbacks); local file = io.open(filename); if( file == nil ) then local err = string.format("Cannot open file \'%s\' for reading.", filename); error(err, 0); end local parse = {} for l in file:lines() do parse.result, parse.msg, parse.line, parse.col, parse.pos = p:parse(l) if (parse.result) then else local fname_short; if( string.len(filename) > 52 ) then fname_short = "..." .. string.sub(filename, -52); else fname_short = filename; end error("XML Parse Error." .. "\nFile: " .. fname_short .. "\nLine: " .. parse.line .. "\nColumn: " .. parse.col .. --"\nAbsolute postion: " .. parse.pos .. "\nMessage: " .. parse.msg, 2) end p:parse("\n"); end p:parse(); p:close(); file:close(); return callbacks.stack[1][1]; end